✍ 공부/TypeScript

[type-challenges] IsNever

Po_tta_tt0 2023. 7. 4. 23:56
반응형

문제

input type으로 T를 받는 IsNever type을 구현하십시오. 만약 T의 유형이 never으로 확인되면 true를 반환하고 아니면 false를 반환합니다

설명

/* _____________ Your Code Here _____________ */

type IsNever<T> = [T] extends [never] ? true : false

/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<IsNever<never>, true>>,
  Expect<Equal<IsNever<never | string>, false>>,
  Expect<Equal<IsNever<''>, false>>,
  Expect<Equal<IsNever<undefined>, false>>,
  Expect<Equal<IsNever<null>, false>>,
  Expect<Equal<IsNever<[]>, false>>,
  Expect<Equal<IsNever<{}>, false>>,
]

 

[T][never]일까?

type IsNever<T> = T extends never ? 'a' : 'b'

type t = IsNever<never> // never
type Never<T> = T extends any ? '무엇인가 출력' : '다른 무엇인가 출력'

type temp = Never<never> // never

 

그런데

type P = never extends never ? 'yes' : 'no' // yes

이 type P는 'yes'를 출력한다.
제네릭 타입에 비밀이 있는게 분명하다

 

공식문서를 보자

type ToArray<Type> = Type extends any ? Type[] : never;

type StrArrOrNumArr = ToArray<string | number>; // type StrArrOrNumArr = string[] | number[]

이 된다

이는, <string | number> 유니언에 있는 멤버 타입들을 모두 돌며 ToArray<T>를 실행시켰기 때문이다.

 

따라서

type StrArrOrNumArr = ToArray<string | number>// 의 결과는
type a = ToArray<string> | ToArray<number>; // 와 같다

 

이러한 📍분배 조건부 유형을 피하기 위해

type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

type StrArrOrNumArr = ToArrayNonDist<string | number>; // (string | number)[]

처럼 extends 키워드의 양 옆을 []로 감싸주어 해결할 수 있다.

 

그럼 never은? union이 아니었는데? 참고

타입스크립트는 조건 타입내부에 있는 유니온 타입을 자동으로 결정한다.
따라서 never은 비어있는 union으로 인식된다(멤버가 없는 유니언)
결국
type IsNever<T> = T extends never ? true : false

라고 작성했을 시,
타입스크립트는 T로 들어온 never은 빈 유니온으로 확인하고 never을 반환하는 것!

 

아하! 🥳

따라서 분배 조건부(never을 빈 union으로 인식하지 못하기 위해) 유형을 피하기 위해
extends의 키워드의 양 옆을 []로 감싸주는 것!

반응형