icon

메티의 블로그

11주차 타입챌린지 스터디
11주차 타입챌린지 스터디

11주차 타입챌린지 스터디

Tags
TypeScript
날짜
Mar 19, 2025
상태
공개

4179 - Flip

문제: Implement the type of just-flip-object. Examples:
Flip<{ a: "x", b: "y", c: "z" }>; // {x: 'a', y: 'b', z: 'c'} Flip<{ a: 1, b: 2, c: 3 }>; // {1: 'a', 2: 'b', 3: 'c'} Flip<{ a: false, b: true }>; // {false: 'a', true: 'b'}
/* _____________ 여기에 코드 입력 _____________ */ // T[K] extends Primitive ? T[K] : never; type Flip<T> = {[K in keyof T as T[K] extends PropertyKey ? T[K] : `${T[K]&boolean}`]: K} type Test = Flip<{ pi: 3.14, bool: true }> /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect, NotEqual } from '@type-challenges/utils' type cases = [ Expect<Equal<{ a: 'pi' }, Flip<{ pi: 'a' }>>>, Expect<NotEqual<{ b: 'pi' }, Flip<{ pi: 'a' }>>>, Expect<Equal<{ 3.14: 'pi', true: 'bool' }, Flip<{ pi: 3.14, bool: true }>>>, Expect<Equal<{ val2: 'prop2', val: 'prop' }, Flip<{ prop: 'val', prop2: 'val2' }>>>, ]
  • 풀이
    • T 순회 돌 때 asT[K] 재정의 하여 뽑아온다.
    • true 라는 key 가 string 형태로 뽑히는게 아니라 boolean 으로 뽑히는 듯하여 조건 고려
  • 배운 점
    • 하지만, T[K]&Primitive 는 안 됨…

4182 - Fibonacci Sequence

문제: Implement a generic Fibonacci<T> that takes a number T and returns its corresponding [Fibonacci number]
/* _____________ 여기에 코드 입력 _____________ */ // 작은 숫자 덧셈 타입 type SmallAdder<A extends number, B extends number, AccA extends never[] = [], AccB extends never[] = []> = AccA['length'] extends A ? AccB['length'] extends B ? [...AccA, ...AccB]['length']: SmallAdder<A, B, AccA, [...AccB, never]>: SmallAdder<A, B, [...AccA, never], AccB>; type SmallAdderTest = SmallAdder<9, 5>; // 작은 숫자 1 빼기 타입 type SmallMinusOne<A extends number, Acc extends never[] = []> = Acc['length'] extends A ? Acc extends [infer _, ...infer Rest] ? Rest['length'] : never : SmallMinusOne<A, [...Acc, never]>; type SmallMinusOneTest = SmallMinusOne<5>; // 피보나치 타입 type Fibonacci<T extends number> = T extends 1 ? 1: T extends 2 ? 1: SmallAdder<Fibonacci<SmallMinusOne<T>>, Fibonacci<SmallMinusOne<SmallMinusOne<T>>>>; type FibonacciTest = Fibonacci<16>; /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<Fibonacci<1>, 1>>, Expect<Equal<Fibonacci<2>, 1>>, Expect<Equal<Fibonacci<3>, 2>>, Expect<Equal<Fibonacci<8>, 21>>, Expect<Equal<Fibonacci<16>, 987>> ]
  • 풀이
    • 작은 숫자 더하기 타입을 T[’length’] 로 만들어서 사용
  • 배운 점
    • 최대 depth 는 16

4260 - AllCombinations

문제:Implement type AllCombinations<S> that return all combinations of strings which use characters from S at most once.
/* _____________ 여기에 코드 입력 _____________ */ type String2Union<S extends String> = S extends `${infer L}${infer R}` ? L | String2Union<R> : S; type AllCombinations<S extends string> = _AllCombinations<String2Union<S>>; type Combination<A extends string, B extends string> = | A | B | `${A}${B}` | `${B}${A}`; type _AllCombinations<A extends string, B extends string = A> = A extends A ? Combination<A, _AllCombinations<Exclude<B, A>>> : never; /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<AllCombinations<''>, ''>>, Expect<Equal<AllCombinations<'A'>, '' | 'A'>>, Expect<Equal<AllCombinations<'AB'>, '' | 'A' | 'B' | 'AB' | 'BA'>>, Expect<Equal<AllCombinations<'ABC'>, '' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'>>, Expect<Equal<AllCombinations<'ABCD'>, '' | 'A' | 'B' | 'C' | 'D' | 'AB' | 'AC' | 'AD' | 'BA' | 'BC' | 'BD' | 'CA' | 'CB' | 'CD' | 'DA' | 'DB' | 'DC' | 'ABC' | 'ABD' | 'ACB' | 'ACD' | 'ADB' | 'ADC' | 'BAC' | 'BAD' | 'BCA' | 'BCD' | 'BDA' | 'BDC' | 'CAB' | 'CAD' | 'CBA' | 'CBD' | 'CDA' | 'CDB' | 'DAB' | 'DAC' | 'DBA' | 'DBC' | 'DCA' | 'DCB' | 'ABCD' | 'ABDC' | 'ACBD' | 'ACDB' | 'ADBC' | 'ADCB' | 'BACD' | 'BADC' | 'BCAD' | 'BCDA' | 'BDAC' | 'BDCA' | 'CABD' | 'CADB' | 'CBAD' | 'CBDA' | 'CDAB' | 'CDBA' | 'DABC' | 'DACB' | 'DBAC' | 'DBCA' | 'DCAB' | 'DCBA'>>, ]
  • 풀이
    • 유니온으로 변경하는 타입, 컴비네이션 생성 타입을 통해 컴비네이션을 구현
 

4425 - Greater Than

문제: In This Challenge, You should implement a type GreaterThan<T, U> like T > U Negative numbers do not need to be considered.
/* _____________ 여기에 코드 입력 _____________ */ // length 를 통해 작은 -1 을 만듬 type SmallMinusOne<A extends number, Acc extends never[] = []> = Acc['length'] extends A ? Acc extends [infer _, ...infer Rest] ? Rest['length'] : never : SmallMinusOne<A, [...Acc, never]>; // 양쪽 다 1씩 빼가며 0 만들기, 먼저 0 이 되었을 때 플래그 리턴 type SmallGreaterThan<T extends number, U extends number> = T extends 0 ? // T == 0 U extends 0 ? // 둘 다 0 false : // T 는 0, U 는 0이 아닐 때 false: // T != 0 U extends 0 ? // U 만 0 true: // 둘 다 0 이 아닐 때 SmallGreaterThan<SmallMinusOne<T>, SmallMinusOne<U>>; type SmallGreaterThanTest = SmallGreaterThan<5,3>; type NumberToTuple<T extends number> = `${T}` extends `${infer First extends number}${infer Rest extends number}` ? [First, ...NumberToTuple<Rest>] : [T]; type NumberToTupleTest = NumberToTuple<234>; // tuple 인 타입 순서대로 크기 검사하기 type GreaterThanSquentially<T extends number[], U extends number[]> = // 자리수 검사 SmallGreaterThan<T['length'], U['length']> extends true ? true : // 배열 검사 T extends [infer TFirst extends number, ...infer TRest extends number[]] ? U extends [infer UFirst extends number, ...infer URest extends number[]] ? // 첫번째 자리 검사 SmallGreaterThan<TFirst, UFirst> extends true ? true: // 아니면 다음 자리 검사 GreaterThanSquentially<TRest, URest>: // 여기로는 빠질리 없어야한다. never: // 자리수 짧음 false; type GreaterThanSquentiallyTest = GreaterThanSquentially<[1,2,4], [1,2,3]>; // 0. 두 수를 비교하기 좋게 전처리하기 위해 숫자를 튜플로 변경 // 1. 자리수 우선 비교 // 2. 자리수가 같으면, 앞자리부터 비교 type GreaterThan<T extends number, U extends number> = GreaterThanSquentially<NumberToTuple<T>, NumberToTuple<U>>; type Test = GreaterThan<4,5>; /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<GreaterThan<1, 0>, true>>, Expect<Equal<GreaterThan<5, 4>, true>>, Expect<Equal<GreaterThan<4, 5>, false>>, Expect<Equal<GreaterThan<0, 0>, false>>, Expect<Equal<GreaterThan<10, 9>, true>>, Expect<Equal<GreaterThan<20, 20>, false>>, Expect<Equal<GreaterThan<10, 100>, false>>, Expect<Equal<GreaterThan<111, 11>, true>>, Expect<Equal<GreaterThan<1234567891011, 1234567891010>, true>>, ]
  • 풀이
    • 두 수를 비교하기 좋게 전처리하기 위해 숫자를 튜플로 변경
    • 자리수를 비교해서 T 가 자리수가 더 많으면 true
    • 자리수가 같으면 앞자리수 부터 비교함
      • 작은 수 비교는 양 수를 1씩 빼가면서 0 에 먼저 도달하는 경우 리턴
      • -1 은 이번엔 한자리씩만 뺄 것이므로 length 로 구현

4471 - Zip

문제: In This Challenge, You should implement a type Zip<T, U>, T and U must be Tuple
/* _____________ 여기에 코드 입력 _____________ */ type Zip<T extends unknown[], U extends unknown[]> = T extends [infer TFirst, ...infer TRest] ? U extends [infer UFirst, ...infer URest] ? [[TFirst, UFirst], ...Zip<TRest, URest>] : []: []; type Test = Zip<[1,2], [true, false]> /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<Zip<[], []>, []>>, Expect<Equal<Zip<[1, 2], [true, false]>, [[1, true], [2, false]]>>, Expect<Equal<Zip<[1, 2, 3], ['1', '2']>, [[1, '1'], [2, '2']]>>, Expect<Equal<Zip<[], [1, 2, 3]>, []>>, Expect<Equal<Zip<[[1, 2]], [3]>, [[[1, 2], 3]]>>, ]
  • 배운 점
    • 두 배열을 한번에 순회하는 방법은 조건부 연산 중첩으로.. 이미 앞에서 써먹었음

4484 - IsTuple

문제: Implement a type IsTuple, which takes an input type T and returns whether T is tuple type.
/* _____________ 여기에 코드 입력 _____________ */ type IsTuple<T> = [T] extends [never] ? false : T extends readonly any[] ? number extends T['length'] ? false : true :false type Test = IsTuple<never> /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<IsTuple<[]>, true>>, Expect<Equal<IsTuple<[number]>, true>>, Expect<Equal<IsTuple<readonly [1]>, true>>, Expect<Equal<IsTuple<{ length: 1 }>, false>>, Expect<Equal<IsTuple<number[]>, false>>, Expect<Equal<IsTuple<never>, false>>, ]
  • 배운 점
    • 튜플은 배열의 길이를 명확하게 가진 것이므로 해당 조건문으로 구별할 수 있다.
    • number extends T['length'] ? false : true