본문 바로가기
Language/Typescript

타입챌린지 : 14-First of Array (easy)

by hsloth 2023. 3. 2.

 

이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.

 

https://github.com/type-challenges/type-challenges/blob/main/questions/00014-easy-first/README.md

 

GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge

Collection of TypeScript type challenges with online judge - GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge

github.com

 

 

설명에는 그냥 Array의 첫 번째 원소를 리턴하면 된다고 나와있었다. 그래서 '어? 개쉽네?' 하고

type First<T extends any[]> = T[0]; 이라고 작성하였으나... 에러 케이스가 있었다.

그래서 type First<T extends any[]> = typeof T === Array ? never : T[0];type First<T extends any[]> = T.length === 0 ? never : T[0]; 도 해봤으나 문법자체가 오류였다.

 

type First<T extends any[]> = T extends [] ? never : T[0];

type First<T extends any[]> = T extends [infer R, ...any[]] ? R : never;

type First<T extends any[]> = T['length'] extends 0 ? never : T[0];

대표적인 답은 위의 세가지라고 볼 수 있다.

type First : First 라는 타입을 정의한다.

<T extends any[]> : T는 any타입의 원소를 갖는 배열이다.

T extends [] ? never : T[0] : T가 빈 배열이면 never를 리턴하고 아니면 T의 첫번째 원소를 반환한다. (삼항연산자, 간단하게 말하면 extends는 === 와 같다고 생각하자)

T extends [infer R, ...any[]] ? R : never : 다음과 같이 생각하면 편하다. 전개 연산자를 사용하여 [firstElement, ...others]로 나눠준 것에서, firstElement는 infer R, ...any[]는 ...others 와 같다. 여기서 infer R을 사용하는 이유는 R이 뭔지 모르기 때문에 infer 키워드를 붙여주는 것이다.(일단, const 처럼 R이라는 것을 정의하기 위해서 사용한다고 생각하자. 타입 레벨에서는 [R, ...any[]] 과 같이 사용이 불가능하다) 따라서, T를 첫번째 원소와 나머지 원소들로 분해할 수 있다면 첫 번째 원소인 R을 리턴하고, 아니라면 never을 리턴한다는 뜻이 된다.

T['length'] extends 0 ? never : T[0] : T는 앞에서 배열이라고 단정을 지었으니, 무조건 length라는 속성이 있다. 따라서 obj[key]와 같은 형태로 T['length']를 써서 해당 속성을 꺼낼 수 있는데, T['length']가 0 이면 never를 리턴하고 아니면 T[0]를 리턴한다는 뜻이다.