Published on

role in

Authors
  • Name
    Twitter

函式多載 (Function Overload)

多個「宣告簽名」(Overload Signatures)

一個「實作簽名」(Implementation Signature)

── 編譯後,只有實作那一段會變成 JavaScript,所有宣告簽名都會被擦除;也就是說,執行時只有一個 filterPersons 函式存在,更不會有名稱衝突。

// Overload 1──當 personType: 'user' 時,回傳 User[]
export function filterPersons(
  persons: Person[],
  personType: 'user',
  criteria: Partial<Omit<User, 'type'>>
): User[];

// Overload 2──當 personType: 'admin' 時,回傳 Admin[]
export function filterPersons(
  persons: Person[],
  personType: 'admin',
  criteria: Partial<Omit<Admin, 'type'>>
): Admin[];

// 實作簽名:接受一般的 Person[]、Person['type'] 和 Partial<Omit<Person,'type'>>
export function filterPersons(
  persons: Person[],
  personType: Person['type'],
  criteria: Partial<Omit<Person, 'type'>>
): Person[] {
  return persons
    .filter((p): p is Extract<Person, { type: typeof personType }> => p.type === personType)
    .filter((person) => {
      const keys = Object.keys(criteria) as Array<keyof typeof person>;
      return keys.every((key) => person[key] === (criteria as any)[key]);
    });
}
const getObjectKeys = <T>(obj: T) => Object.keys(obj) as (keyof T)[];

export function filterPersons(persons: Person[], personType: User['type'], criteria: Partial<Omit<User, 'type'>>): User[];
export function filterPersons(persons: Person[], personType: Admin['type'], criteria: Partial<Omit<Admin, 'type'>>): Admin[];
export function filterPersons(persons: Person[], personType: Person['type'], criteria: Partial<Person>): Person[] {
    return persons
        .filter((person) => person.type === personType)
        .filter((person) => {
            let criteriaKeys = getObjectKeys(criteria);
            return criteriaKeys.every((fieldName) => {
                return person[fieldName] === criteria[fieldName];
            });
        });
}