View on GitHub: https://tsch.js.org/15
배열 T를 사용하고 마지막 요소를 반환하는 제네릭 Last<T>
를 구현합니다.
예시
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type tail1 = Last<arr1>; // expected to be 'c'
type tail2 = Last<arr2>; // expected to be 1
type Last<T extends any[]> = T extends [...infer Rest, infer LastElement]
? LastElement
: never;
View on GitHub: https://tsch.js.org/16
배열 T를 사용해 마지막 요소를 제외한 배열을 반환하는 제네릭 Pop<T>
를 구현합니다.
예시
type arr1 = ["a", "b", "c", "d"];
type arr2 = [3, 2, 1];
type re1 = Pop<arr1>; // expected to be ["a", "b", "c"];
type re2 = Pop<arr2>; // expected to be [3, 2];
type Pop<T extends any[]> = T extends [...infer Rest, infer Last] ? Rest : [];
View on GitHub: https://tsch.js.org/20
Type the function PromiseAll
that accepts an array of PromiseLike objects, the returning value should be Promise<T>
where T
is the resolved result array.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise<string>((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
// expected to be `Promise<[number, 42, string]>`
const p = PromiseAll([promise1, promise2, promise3] as const);
type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T;
declare function PromiseAll<T extends any[]>(
values: readonly [...T]
): Promise<{
[K in keyof T]: Awaited<T[K]>;
}>;
에러 케이스
declare function PromiseAll<T extends any[]>(
values: T
): Promise<{ [K in keyof T]: T[K] extends Promise<infer U> ? U : T[K] }>;
PromiseAll
함수는 배열의 각 요소를 Promise
로 감싸서 반환하는 함수T
는 any[]로 받고, 이를 튜플로(readonly)로 변환하기 위해 readonly [...T]
를 사용Promise
로 감싸서 반환하기 위해 Promise<{ [K in keyof T]: Awaited<T[K]>; }>
를 사용{ [K in keyof T]: Awaited<T[K]> }
는 배열의 각 요소를 순회하며 키를 추출하고, 각 요소를 Awaited<T[K]>
로 변환하여 반환Awaited<T[K]>
는 T[K]
가 Promise
라면 Promise
의 내부 타입을 추출하고, 그렇지 않다면 T[K]
를 반환values에 readonly [...T]가 가능한 이유는?
T extends any[]
에서 T
는 배열이지만 튜플이 될 수도 있고, 일반 배열이 될 수도 있음readonly [...T]
를 사용하여 튜플로 변환declare function Example<T extends any[]>(values: readonly [...T]): T;
declare function Example2<T extends any[]>(values: T): T;
const test1 = Example([1, 2, 3]); // T = [number, number, number] (튜플)
const test2 = Example2([1, 2, 3]); // T = number[] (일반 배열)
readonly [...T]
에 맞춰 T
를 튜플로 유추하려고 시도함values
가 일반 배열(number[]
)이면 TypeScript는 가능한 한 readonly
속성을 유지하려고 함T
는 [number, number, number]
처럼 튜플로 추론됨readonly
옵션을 붙여주지 않으면 Example2
처럼 일반 배열로 추론됨왜 Awaited가 필요한가?
T[K] extends Promise<infer U> ? U : T[K]
를 사용하면 오류 발생extends
)를 사용할 때, T
가 유니온(A | B
)이면 각각 개별적으로 평가한 후, 결과를 다시 유니온으로 합침T[K]
자체가 유니온 타입이기 때문에(이 문제에서는 number | Promise<number>
), T[K]
가 리턴될 경우 number | Promise<number>
로 추론되어 오류 발생Awaited<T[K]>
를 사용하여 T[K]
가 리턴될 경우 number
로 추론되도록 함View on GitHub: https://tsch.js.org/62
때때로 유니온 타입의 특정 속성을 기준으로 조회할 수도 있습니다.
이 챌린지에서는 유니온 타입 Cat | Dog
에서 공통으로 사용하는 type
필드를 기준으로 해당하는 타입을 얻고자 합니다. 다시 말해서, 다음 예시에서는 LookUp<Cat | Dog, 'dog'>
으로 Dog
타입을, LookUp<Cat | Dog, 'cat'>
으로 Cat
타입을 얻을 수 있습니다.
interface Cat {
type: "cat";
breeds: "Abyssinian" | "Shorthair" | "Curl" | "Bengal";
}
interface Dog {
type: "dog";
breeds: "Hound" | "Brittany" | "Bulldog" | "Boxer";
color: "brown" | "white" | "black";
}
type MyDogType = LookUp<Cat | Dog, "dog">; // 기대되는 결과는 `Dog`입니다.
type LookUp<U, T> = U extends { type: T } ? U : never;
U
를 분배법칙을 이용해 타입 조회U
가 { type: T }
형태를 포함하는지 확인U
를 반환never
반환View on GitHub: https://tsch.js.org/106
정확한 문자열 타입이고 시작 부분의 공백이 제거된 새 문자열을 반환하는 TrimLeft<T>
를 구현하십시오.
type trimed = TrimLeft<" Hello World ">; // expected to be 'Hello World '
type TrimLeft<S extends string> = S extends `${" " | "\n" | "\t"}${infer Rest}`
? TrimLeft<Rest>
: S;
S
가 " " | "\n" | "\t"
로 시작하는지 확인S
에서 시작 부분의 공백을 제거한 새 문자열(Rest
)을 반환S
를 그대로 반환View on GitHub: https://tsch.js.org/108
정확한 문자열 타입이고 시작 부분의 공백이 제거된 새 문자열을 반환하는 Trim<T>
를 구현하십시오.
type trimmed = Trim<" Hello World ">; // expected to be 'Hello World'
type TrimLeft<S extends string> = S extends `${" " | "\n" | "\t"}${infer Rest}`
? TrimLeft<Rest>
: S;
type TrimRight<S extends string> = S extends `${infer Rest}${" " | "\n" | "\t"}`
? TrimRight<Rest>
: S;
type Trim<S extends string> = TrimRight<TrimLeft<S>>;
TrimLeft<S>
활용해 문자열 S
에서 시작 부분의 공백을 제거한 새 문자열을 반환TrimRight<S>
를 정의해 문자열 S
에서 끝 부분의 공백을 제거한 새 문자열을 반환Trim<S>
: TrimLeft<S>
와 TrimRight<S>
를 조합하여 문자열 S
에서 양쪽 끝의 공백을 제거한 새 문자열을 반환