TypeScript - Function Overload

이소라·2022년 7월 16일
0

TypeScript

목록 보기
8/28

Function Overload

  • overload signature를 사용하여 함수를 다양한 방식으로 호출할 수 있음
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3); // Error: No overload expects 2 arguments
  • 함수를 호출할 때 하나의 overload만 고려함
function len(s: string): number;
function len(arr: any[]): number;
function len(x: any) {
  return x.length;
}

len(""); // OK
len([0]); // OK
len(Math.random() > 0.5 ? "hello" : [0]); // Error
  • 같은 인자 수와 같은 반환 타입을 가진 overload의 경우, overload가 아니라 union 타입을 쓰는 것이 좋음
function len(x: any[] | string) {
  return x.length;
}



Do's and Don't

❌ Callback의 인자만 다른 overload를 분리해서 사용하지 않기

/* WRONG */
declare function beforeAll(action: () => void, timeout?: number): void;
declare function beforeAll(
  action: (done: DoneFn) => void,
  timeout?: number
): void;

✅ 모든 인자를 포함하는 callback을 사용하는 하나의 overload 사용하기

/* OK */
declare function beforeAll(
  action: (done: DoneFn) => void,
  timeout?: number
): void;

❌ 일반적인 overloads를 구체적인 overloads 전에 넣지 않기

  • 이유 : 타입스크립트는 함수를 호출할 때 처음으로 맞는 overload를 고르므로, 더 일반적인 overload를 먼저 선언할 경우 그 이후 선언되는 overload가 감춰지고 부를수 없게 됨
/* WRONG */
declare function fn(x: unknown): unknown;
declare function fn(x: HTMLElement): number;
declare function fn(x: HTMLDivElement): string;
var myElem: HTMLDivElement;
var x = fn(myElem); // x: unknown, wat?

✅ 구체적인 overloads 이후에 일반적인 overload를 넣기

/* OK */
declare function fn(x: HTMLDivElement): string;
declare function fn(x: HTMLElement): number;
declare function fn(x: unknown): unknown;
var myElem: HTMLDivElement;
var x = fn(myElem); // x: string, :)

❌ 뒤따르는 매개변수만 다른 여러 overloads를 쓰지 않기

/* WRONG */
interface Example {
  diff(one: string): number;
  diff(one: string, two: string): number;
  diff(one: string, two: string, three: boolean): number;
}

✅ 가능하면 optional 매개변수를 사용하기

/* OK */
interface Example {
  diff(one: string, two?: string, three?: boolean): number;
}

❌ 한 인자에서만 타입이 다른 overloads 쓰지 않기

  • 이유 : 한번에 하나의 overload만 고려하기 때문에, 한 인자의 타입이 2개 이사인 경우 여러 overloads를 쓰기보다는 union 타입을 쓰는 것을 권장함
/* WRONG */
interface Moment {
  utcOffset(): number;
  utcOffset(b: number): Moment;
  utcOffset(b: string): Moment;
}

✅ 가능하면 union 타입을 사용하기

/* OK */
interface Moment {
  utcOffset(): number;
  utcOffset(b: number | string): Moment;

0개의 댓글