[TypeScript] Call Signature 와 Index Signature
📌 호출 시그니쳐(Call Signature)
Call Signature란 함수의 매개변수와 반환 값의 타입을 type 또는 interface 로 미리 선언하는 것입니다.
즉, 함수의 구현이 아닌, 함수의 타입을 정의하는 것입니다.
일반적인 함수 선언 방법은 다음과 같습니다.
function add(a: number, b: number): number {
return a + b;
}
const sub = (a: number, b: number): number => {
return a - b;
};
이를 호출 시그니쳐를 이용하여 표현하면 다음과 같습니다.
type Operation = (a: number, b: number) => number;
const add: Operation = (a, b) => a + b;
const sub: Operation = (a, b) => a - b;
console.log(add(1, 2));
console.log(sub(1, 2));
interface Operation {
(a: number, b: number): number;
}
const add: Operation = (a, b) => a + b;
const sub: Operation = (a, b) => a - b;
console.log(add(1, 2));
console.log(sub(1, 2));
✅ 오버로딩 (Overloading)
함수 오버로딩은 함수 이름은 동일하고 매개 변수만 다른 여러 개의 함수를 정의하는 것을 말합니다.
매개 변수의 타입이 다른 경우에 마지막 줄은 에러를 발생시킵니다.
a 타입은 (number | string) 인데, number 와 string 은 더할 수가 없어서 에러가 발생됩니다.
interface Add {
(a: number, b: number): number;
(a: string, b: number): number;
}
const add: Add = (a, b) => a + b; // Error!
// '+' 연산자를 'string | number' 및 'number' 형식에 적용할 수 없습니다.
이때 변수의 타입 별로 처리를 해야합니다. a 타입이 number 일 때는 a + b 를, a 타입이 string 일 때는 b 를 리턴합니다.
const add: Add = (a, b) => {
if (typeof a === "number") {
return a + b;
} else return b;
};
매개 변수의 개수가 다른 경우, optional 변수로 설정합니다. 이때 optional 변수로 설정한 변수에는 타입을 꼭 지정해 주어야 합니다.
interface Add {
(a: number, b: number): number;
(a: string, b: number): number;
(a: number, b: number, c: number): number;
}
const add: Add = (a, b, c?: number) => {
if (typeof a === "number") {
if (c) return a + b + c;
else return a + b;
} else return b;
};
📌 인덱스 시그니쳐(Index Signature)
Index Signature 는 { [Key: Type]: valueType } 형식으로 구성되며, type 또는 interface 키워드로 정의할 수 있습니다.
객체가 여러 Key 를 가질 수 있으며, Key 와 매핑되는 Value 를 가지는 경우 사용됩니다.
주의해야할 점은, Key 타입으로 string, number, symbol, Template literal 만 가능합니다.
type Type1 = {
[key: string]: unknown;
};
interface Type2 {
[key: number]: string;
}
let obj: Type1 = {
name: "John",
age: 20,
};
obj["description"] = "Hello world";
console.log(obj); // { name: 'John', age: 20, description: 'Hello world' }
또한 다음과 같이 객체 내부에 존재하는 속성의 값을 모두 합산해야하는 경우, 인덱스 시그니쳐를 사용하여 함수의 매개변수 타입으로 지정합니다.
let fees = {
taxi: 4800,
subway: 1400,
bus: 1250,
};
function addFees(fees: { [key: string]: number }) {
let ret: number = 0;
for (let key in fees) {
ret += fees[key];
}
return ret;
}
인덱스 시그니쳐의 Key 타입이 number 일 경우, 배열처럼 사용이 가능합니다.
interface Type {
[key: number]: string;
}
let tmp1: Type = {};
let tmp2: Type = [];
tmp1[0] = "Hello"; // { 0: "Hello" }
tmp2[0] = "World"; // ["World"]
let tmp3: Type = ["Hello", "World"];
Key 타입이 여러 개인 경우 다음과 같이 사용합니다.
interface Type {
[index: number]: string;
[key: string]: string;
}
let temp: Type = {
0: "Hello",
description: "World",
};
console.log(temp); // { 0: "Hello", description: "World" }
✅ Index Signature 를 사용하는 경우
- 객체의 특정 value 에 접근하고 싶을 때
- 객체의 속성들(key, value)의 모든 이름이나 type을 명확히 알지 못할 때, 속성의 type만 우선 지정해주어 객체의 정보들에 접근하기 위해 사용
- 속성의 type 만 알고있는 경우