
<T>ReturnType 타입은 함수의 리턴값의 타입을 지정해주는 유틸리티 타입이다. Generic 인자로 typeof 키워드와 함께 추론할 함수를 넣어주면, 해당 함수의 리턴 타입을 반환한다.
type T0 = ReturnType<() => string> // string
type T1 = ReturnType<(s: string) => void> // void
type T2 = ReturnType<<T>() => T> // unknown
type T3 = ReturnType<<T extends number[]>(...args: T) => T>; // number[]
Functuon 타입을 인자로 전달하면 다음의 에러가 발생한다.
type T8 = ReturnType<Function>;
// Type 'Function' provides no match for the signature '(...args: any): any'.
<T>함수 타입에서 매개변수의 타입들을 추출하여 새로운 튜플 타입(tuple type)을 생성시켜준다.
const logDetails = (a: string, b: number): void => {
console.log(`a: ${a}, b: ${b}`);
};
// Parameters 유틸리티 타입을 사용해 매개변수 타입 추출
type LogDetailsParams = Parameters<typeof logDetails>; // [a: string, b: number]
// wrapperFunction 함수를 화살표 함수로 변환
const wrapperFunction = (...args: LogDetailsParams): void => {
console.log('Calling logDetails with:', args);
logDetails(...args);
};
<T>클래스 타입에서 해당 클래스의 인스턴스 타입을 추출하는 데 사용된다. 즉, 특정 클래스의 인스턴스를 생성했을 때 그 인스턴스가 가지게 되는 타입을 얻어낼 수 있다. 이 유틸리티 타입은 클래스 자체가 아닌, 클래스의 인스턴스가 어떤 타입을 가지는지를 알고 싶을 때 유용하다. 하지만 클래스 타입에만 사용 가능하며, 생성자를 정의하지 않은 클래스는 제한된다.
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name}.`;
}
}
// `ExampleInstanceType`는 `ExampleClass`의 인스턴스 타입이 된다.
type UserType = InstanceType<typeof User>;
const instance: UserType = new User ('John', 30);
console.log(instance.greet()); // 출력: Hello, my name is John.
js에서의 Class 는 두가지 타입을 가진다. 값이면서도 타입이기도 한다. 하지만 이 두가지는 전혀 다른 걸 가르킨다.
User 클래스는 인스턴스 의 타입이고 (new User()로 만들어지는 객체의 타입)typeof User 생성자 타입이다. 이 클래스를 new 로 호출할 수 있다는 그 자체의 타입이다.그렇다면, 보통은 그냥 User 타입을 그냥 쓰면 되지 않나? 왜 굳이 InstanceType<typeof User> 이렇게 쓰는 거지? 라고 할 수 있다. 하지만 "클래스를 변수로 받아서" 동작하는 제너릭 코드에서는 말이 달라진다.
const create = <T extends new (...args: any[]) => any>(
ctor: T,
...args: ConstructorParameters<T>
): InstanceType<T> => {
return new ctor(...args);
};
// 사용법
class Dog {
constructor(public name: string) {}
bark() {
console.log(`${this.name} says woof`);
}
}
const d = create(Dog, 'Buddy'); // d: Dog
d.bark(); // Buddy says woof
이 create 함수의 흐름은 다음과 같다.
T는 클래스 생성자 타입ConstructorParameters 는 생성자의 인자를 추출해주는 유틸리티 타입하지만 대부분의 상황에선, 클래스 그 자체를 타입으로 쓰기에 InstanceType 을 사용하는 경우는 많지 않다. 사실 위의 예제는 저 유틸리티 타입을 어거지로 쓰는 느낌이 없지않아 있긴 하다..