본문 바로가기
Language/Typescript

타입챌린지 : 3243-FlattenDepth (medium)

by hsloth 2023. 5. 30.

 

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

 

https://github.com/type-challenges/type-challenges

 

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

 

제네릭으로 배열과 Depth를 받아서, Depth만큼만 배열을 Flat하는 타입이다.

재귀를 어떻게 할지 방향성만 잡으면 생각보다 쉽다.

type FlattenDepth<T, N extends number = 1, U extends any[] = []> = U['length'] extends N ?
  T :
  T extends [infer F, ...infer O] ?
  F extends any[] ? [...FlattenDepth<F, N, [...U, 0]>, ...FlattenDepth<O, N, U>] :
  [F, ...FlattenDepth<O, N, U>] : T

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

type cases = [
  Expect<Equal<FlattenDepth<[]>, []>>,
  Expect<Equal<FlattenDepth<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<FlattenDepth<[1, [2]]>, [1, 2]>>,
  Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2>, [1, 2, 3, 4, [5]]>>,
  Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, [[5]]]>>,
  Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 3>, [1, 2, 3, 4, [5]]>>,
  Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 19260817>, [1, 2, 3, 4, 5]>>,
]

type FlattenDepth<T, N extends number = 1, U extends any[] = []> : FlattenDepth라는 타입을 정의하는데 N은 Depth를 가리키고, 기본값이 1이고, U는 length비교를 통해 Depth를 확인하는 용도이다.

U['length'] extends N ? T : U의 길이가 N과 같으면 T를 바로 리턴하고 아니라면,

T extends [infer F, ...infer O] : T에서 첫번째 원소 F를 꺼내고

F extends any[] ? : F가 배열 형식이면

[...FlattenDepth<F, N, [...U, 0]>, ...FlattenDepth<O, N, U>] : 배열 F를 한 번 더 Flat해주기 위해 재귀하고, 나머지 O도 Flat을 해준다. 여기서 F는 이미 한 번 Flat되었기 때문에 U에 원소 하나를 추가해서 재귀를 돌리고, O의 경우는 Flat을 안했기 때문에 U를 그대로 가져간다.

[F, ...FlattenDepth<O, N, U>] : T : F가 배열이 아니라면 F는 그대로 리턴하고, FlattenDepth<O, N, U>를 통해 나머지를 마저 Flat한다. 그리고 T가 배열이 아니라면 T를 리턴한다.