본문 바로가기
Language/Typescript

타입챌린지 : 459-Flatten (medium)

by hsloth 2023. 4. 6.

 

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

 

https://github.com/type-challenges/type-challenges/blob/main/questions/00459-medium-flatten/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

 

제네릭 인자로 들어오는 배열 값의 원소에 배열이 있다면, 배열을 모두 제거해서 하나의 배열로 리턴하는 타입이다.

 

일단, 내가 생각한 첫 번째 답변을 봐보자.

type Flatten<T extends any[]> = T extends [infer F, ...infer O] ? 
	(F extends any[] ? 
    [...F, ...Flatten<O>] : [F, ...Flatten<O>]) : 
    [];

T가 배열이고, T의 첫 번째 원소가 배열이면 전개연산자를 이용해 재귀하는 형태로 작성해보았다.

하지만, 테스트케이스 4번에서 에러가 났다.

Flatten<[1, 2, [3, 4], [[[5]]]> 에서 [[[5]]]가 제대로 Flat이 되지 않았다... 배열 하나만 벗겨지고 나머지는 벗겨지지 않았다.

 

그 이유는 바로, F가 배열이 겹쳐있을 때 단순히 ...F로만 전개해주면 안되고, Flatten을 재귀를 이용해서 또 한 번 Flat해주어야 한다.

그리서 최종 답은 이렇다.

type Flatten<T extends any[]> = T extends [infer F, ...infer O] ?
	(F extends any[] ? [...Flatten<F>, ...Flatten<O>] : 
	[F, ...Flatten<O>]) : 
	[];

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

type cases = [
  Expect<Equal<Flatten<[]>, []>>,
  Expect<Equal<Flatten<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<Flatten<[1, [2]]>, [1, 2]>>,
  Expect<Equal<Flatten<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, 5]>>,
  Expect<Equal<Flatten<[{ foo: 'bar'; 2: 10 }, 'foobar']>, [{ foo: 'bar'; 2: 10 }, 'foobar']>>,
]

T extends [infer F, ...infer O] ? : T가 첫 번째 원소 F와 나머지 배열 O로 나뉠 때, (여기서 T가 원소가 하나인 배열이어도 해당된다)

F extends any[] ? : F가 배열이라면,

[...Flatten<F>, ...Flatten<O>] : F를 재귀로 Flatten해주고(F가 배열이 여러겹 일 수 떄문에... [[[F]]] 같이.), O도 재귀로 Flatten 해준다.

[F, ...Flatten<O>] : F가 배열이 아니라면 F를 그대로 리턴하고, 나머지는 Flatten해준다.

[] : T가 배열이 아니라면(마지막 재귀에서) 빈 배열을 리턴한다.