본문 바로가기
Language/Typescript

타입챌린지 : 949-AnyOf (medium)

by hsloth 2023. 4. 18.

 
이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.
 
https://github.com/type-challenges/type-challenges/blob/main/questions/00949-medium-anyof/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

 
제네릭에 배열인자를 받고, 배열의 원소 중 하나라도 falsy한 값이 없으면 true를 리턴하고, 모두 falsy한 값이면 false를 리턴하는 타입이다.
 
풀다가 어? 이게 왜안되지? 하고 계속 고민하다가 결국 답을 봐버렸다...
그리고 답을 보고서는 '아...! 내가 멍청했다' 라고 생각했다....
 
우선 나의 처음 답을 봐보자.

// 물론 오답이다.
type Blank = [] | null | undefined | 0 | false | '' | {}


type AnyOf<T extends readonly any[]> = T extends [infer F, ...infer O] ? 
	F extends Blank ? AnyOf<O> : true : false;

 
 
다른 건 다 되는데 여기서 저 망할 {} 가 문제였다. 
1 extends {} 가 true로 나왔다. ㅋㅋㅋ 요건 몰랐지....... 뭐든 {}를 상속하면 true가 뜨더라...
그래서 {} 대신 object로 바꿨는데... 이건 또 말이 안된다... 그래서 어떻게 하지 계속 고민을 하다가 답을 봤다.
 

type Blank = [] | null | undefined | 0 | false | '' | {[key: string]: never}

type AnyOf<T extends readonly any[]> = T extends [infer F, ...infer O] ? 
	F extends Blank ? AnyOf<O> : true : false;

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

type cases = [
  Expect<Equal<AnyOf<[1, 'test', true, [1], { name: 'test' }, { 1: 'test' }]>, true>>,
  Expect<Equal<AnyOf<[1, '', false, [], {}]>, true>>,
  Expect<Equal<AnyOf<[0, 'test', false, [], {}]>, true>>,
  Expect<Equal<AnyOf<[0, '', true, [], {}]>, true>>,
  Expect<Equal<AnyOf<[0, '', false, [1], {}]>, true>>,
  Expect<Equal<AnyOf<[0, '', false, [], { name: 'test' }]>, true>>,
  Expect<Equal<AnyOf<[0, '', false, [], { 1: 'test' }]>, true>>,
  Expect<Equal<AnyOf<[0, '', false, [], { name: 'test' }, { 1: 'test' }]>, true>>,
  Expect<Equal<AnyOf<[0, '', false, [], {}, undefined, null]>, false>>,
  Expect<Equal<AnyOf<[]>, false>>,
]

나는 재귀로 이 문제를 접근했다.
T extends [infer F, ...infer O] ? : T가 배열일 때,
F extends Blank ? : 첫번째 원소 F가 Blank를 상속한다면,
AnyOf<O> : true : false : 나머지 원소들을 AnyOf로 재귀시킨다. Blank를 상속하지 않는다면 true를 내뱉는다. 그리고 마지막 원소까지 재귀로 순회했다면, false를 내뱉는다.