dev-hamster
[type-challengs] easy 10-14 본문
Includes
JavaScript의 Array.includes 함수를 타입 시스템에서 구현하세요. 타입은 두 인수를 받고, true 또는 false를 반환하자.
U가 T의 구성 요소인지 확인하기 위해 T를 인덱스 접근 타입으로 변경하고 U가 이 유니온 타입에 속하는지 조건부로 true 또는 false를 반환한다. 그런데 이 코드는 primitive type만 통과하고 객체나 타입 자체는 통과하지 않는다. 예를 들어 { a: 'A'} 는 { }의 서브 타입으로 true를 반환한다.
// 오답
type Includes<T extends readonly unknown[], U> = U extends T[number] ? true : false;
T 배열의 요소를 키로 갖는 타입을 만들고 U가 T의 키인지 확인하면 해결할 수 있을 것 같지만, U가 프로퍼티 키로 사용할 수 있을 때만 통과된다. (참고)
// 오답
type Includes<T extends readonly any[], U> = {
[P in T[number]]: true
}[U] extends true ? true : false;
이를 해결하기 위해 배열의 첫번째 요소와 타입이 같은지 재귀적으로 타입을 확인해야 한다.
// 정답
type Includes<T extends readonly unknown[], U> =
T extends [infer First, ...infer Rest]
? Equal<First, U> extends true ? true : Includes<Rest, U>
: false;
infer키워드를 복습하고 가자.infer은 조건부 타입에서 참으로 평가될 때 사용할 수 있는 타입을 추론하는 데 사용한다.
참고로 @type-challenges/utils 의 Equal은 아래처럼 구현되어 있다.
Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
Push
Array.push의 제네릭 버전을 구현하자.
T를 배열로 타입을 제한하고 배열 디스트럭쳐링을 이용해 배열 타입을 반환한다.
type Push<T extends unknown[], U> = [...T, U];
Unshift
Array.unshift의 타입 버전을 구현하자.
Push 문제와 동일하다. T와 U 순서만 바꿔주면 된다.
type Unshift<T extends unknown[], U> = [U, ...T];
Parameters
내장 제네릭 Parameters<T>를 이를 사용하지 않고 구현하자.
조건부 타입으로 함수 타입이라면 args를 추론한 D 타입을 반환한다. 하지만 T타입이 함수로 제한하지 않아 함수가 아닌 타입에서 에러가 나지 않아서 아쉽다.
type MyParameters<T> = T extends (...args: infer D) => unknown ? D : any;
const temp = ['1'];
type x = MyParameters<typeof temp>; // 타입 에러가 나지 않는다.
이를 막으려면 T타입을 함수로 제한하면 된다.
type MyParameters<T extends (...args: any[]) => any> = T extends (...any: infer S) => any ? S : any '타입스크립트 > type-challenges' 카테고리의 다른 글
| [type-challenges] medium 10-13 (0) | 2024.10.22 |
|---|---|
| [type-chllenges] medium 05-08 (2) | 2024.10.22 |
| [type-challenges] medium 01-04 (0) | 2024.10.17 |
| [type-challenges] easy 06-09 (1) | 2024.10.11 |
| [type-challenges] easy 01-05 (2) | 2024.10.11 |