배열(튜플) T를 받아 첫 원소의 타입을 반환하는 제네릭 First<T>를 구현하세요.
type First<T extends any[]> =
T extends [infer First,...infer Rest]?
First
:never;
[infer First,...infer Rest]를 사용해서 첫 번째로 오는 타입을 참인 분기에서 사용할 수 있었다.
만약 T에 빈 배열 타입이 들어올 경우에는 T extends [infer First,...infer Rest]가 거짓으로 판별된다.
문제에서는
First<[]>의 타입을 never로 지정하였으므로, 거짓인 분기에서 never를 사용하게 하였다.
// @ts-expect-error
First<'notArray'>,
// @ts-expect-error
First<{ 0: 'arrayLike' }>,
배열이 아닌 경우에는 에러가 나야하는 제약 조건도, <T extends any[]> 제네릭을 사용하여 배열만 들어올 수 있게끔 제약을 주었다.
infer과 관련된 개념이 나왔다
infer은 ${검사하는 타입} extends ${조건}?${참인 경우의 타입}:${거짓인 경우의 타입}와 같은 삼항 연산 타입에서 조건 부분에 들어갈 수 있는 사설(?)타입이다.
이때 조건에서 infer이 제시된 형태와 ${검사하는 타입}이 같다면
${참인 경우의 타입}에서 infer에서 이름 붙인 타입 명을 사용할 수 있다.
//answer1
type First<T extends any[]> = T extends [] ? never : T[0]
//answer2
type First<T extends any[]> = T['length'] extends 0 ? never : T[0]
이와 같은 풀이 방식도 존재했다.
첫 번째 풀이는 T가 빈 배열일 경우 never, 아니면 T[0]을 사용하게 두었고,
두 번째 풀이는 T['length']가 0인 경우 never, 아니면 T[0]을 사용하게 두었다.
참고로 타입이 튜플이 아니라 number[]와 같은 형태이거나, 리터럴 string의 legnth 프로퍼티는 숫자 리터럴 타입이 아니라, number임에 주의하여야 한다