카테고리 없음

타입챌린지 [쉬움] 난이도 중 인사이트 정리

haeunkim.on 2025. 5. 27. 18:50

✅ 1. 14 - First

문제: 배열의 첫 번째 요소의 타입을 추출하라.

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3

type cases = [
  Expect<Equal<First<[3, 2, 1]>, 3>>,
  Expect<Equal<First<[() => 123, { a: string }]>, () => 123>>,
  Expect<Equal<First<[]>, never>>,
  Expect<Equal<First<[undefined]>, undefined>>,
]

type errors = [
  // @ts-expect-error
  First<'notArray'>,
  // @ts-expect-error
  First<{ 0: 'arrayLike' }>,
]
type First<T extends any[]> = T extends [] ? never : T[0];
  • 빈 배열이면 never, 아니면 T[0]으로 첫 요소 반환
  • 배열 제약: T extends any[]

✅ 2. 43 - Exclude

문제: 유니언 타입 T에서 U에 해당하는 타입을 제거하라.

type cases = [
  Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a'>, 'b' | 'c'>>,
  Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a' | 'b'>, 'c'>>,
  Expect<Equal<MyExclude<string | number | (() => void), Function>, string | number>>,
]
type MyExclude<T, U> = T extends U ? never : T;
  • 핵심: 조건부 타입의 분산 성질
  • 'a' | 'b' | 'c', 'a' → 'b' | 'c'

✅ 3. 189 - Awaited

문제: Promise 타입에서 내부 값을 꺼내라 (재귀적으로).

type X = Promise<string>
type Y = Promise<{ field: number }>
type Z = Promise<Promise<string | number>>
type Z1 = Promise<Promise<Promise<string | boolean>>>
type T = { then: (onfulfilled: (arg: number) => any) => any }

type cases = [
  Expect<Equal<MyAwaited<X>, string>>,
  Expect<Equal<MyAwaited<Y>, { field: number }>>,
  Expect<Equal<MyAwaited<Z>, string | number>>,
  Expect<Equal<MyAwaited<Z1>, string | boolean>>,
  Expect<Equal<MyAwaited<T>, number>>,
]
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U> 
	? U extends PromiseLike<any> 
    	? MyAwaited<U> 
        : U 
    : never;
  • infer로 내부 타입 꺼냄
  • 중첩된 Promise도 재귀로 처리
  • PromiseLike 제약으로 thenable 대응

✅ 4. 533 - Concat

문제: 배열 T, U를 이어붙인 결과 타입을 만들라.

const tuple = [1] as const

type cases = [
  Expect<Equal<Concat<[], []>, []>>,
  Expect<Equal<Concat<[], [1]>, [1]>>,
  Expect<Equal<Concat<typeof tuple, typeof tuple>, [1, 1]>>,
  Expect<Equal<Concat<[1, 2], [3, 4]>, [1, 2, 3, 4]>>,
  Expect<Equal<Concat<['1', 2, '3'], [false, boolean, '4']>, ['1', 2, '3', false, boolean, '4']>>,
]

// @ts-expect-error
type error = Concat<null, undefined>
type Concat<T extends readonly unknown[], U extends readonly unknown[]> = [...T, ...U];
  • 튜플 스프레드로 간단히 병합

✅ 5. 898 - Includes

문제: 배열 T에 타입 U가 포함되어 있는지 확인하라 (Equal 기준).

type cases = [
  Expect<Equal<Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Kars'>, true>>,
  Expect<Equal<Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'>, false>>,
  Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 7>, true>>,
  Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 4>, false>>,
  Expect<Equal<Includes<[1, 2, 3], 2>, true>>,
  Expect<Equal<Includes<[1, 2, 3], 1>, true>>,
  Expect<Equal<Includes<[{}], { a: 'A' }>, false>>,
  Expect<Equal<Includes<[boolean, 2, 3, 5, 6, 7], false>, false>>,
  Expect<Equal<Includes<[true, 2, 3, 5, 6, 7], boolean>, false>>,
  Expect<Equal<Includes<[false, 2, 3, 5, 6, 7], false>, true>>,
  Expect<Equal<Includes<[{ a: 'A' }], { readonly a: 'A' }>, false>>,
  Expect<Equal<Includes<[{ readonly a: 'A' }], { a: 'A' }>, false>>,
  Expect<Equal<Includes<[1], 1 | 2>, false>>,
  Expect<Equal<Includes<[1 | 2], 1>, false>>,
  Expect<Equal<Includes<[null], undefined>, false>>,
  Expect<Equal<Includes<[undefined], null>, false>>,
]
type Includes<T extends readonly unknown[], U> = T extends [infer First, ...infer Rest] 
	? Equal<First, U> extends true 
    	? true 
        : Includes<Rest, U> 
    : false;
  • 재귀로 배열 탐색
  • Equal을 사용해 타입 동등성 비교

✅ 6. 3312 - Parameters

문제: 함수 타입의 파라미터 튜플을 추출하라 (Parameters 직접 구현).

function foo(arg1: string, arg2: number): void {}
function bar(arg1: boolean, arg2: { a: 'A' }): void {}
function baz(): void {}

type cases = [
  Expect<Equal<MyParameters<typeof foo>, [string, number]>>,
  Expect<Equal<MyParameters<typeof bar>, [boolean, { a: 'A' }]>>,
  Expect<Equal<MyParameters<typeof baz>, []>>,
]
type MyParameters<T extends (...args: any[]) => any> 
	= T extends (...args: infer P) => any 
    	? P 
        : never;
  • infer P로 매개변수 목록 추출
  • 함수 타입 제약: T extends (...args: any[]) => any
반응형