[TS] Type-Challenges 스터디 17주차

유한별·2025년 5월 13일
0

타입 챌린지 스터디

목록 보기
17/19
post-thumbnail

[medium] 26401. JSON Schema to TypeScript

View on GitHub: https://tsch.js.org/26401

문제

Implement the generic type JSONSchema2TS which will return the TypeScript type corresponding to the given JSON schema.

Additional challenges to handle:

  • additionalProperties
  • oneOf, anyOf, allOf
  • minLength and maxLength

문제 설명

  • 주어진 JSON Schema를 TypeScript 타입으로 변환하는 문제
  • 추가 챌린지
    • additionalProperties
    • oneOf, anyOf, allOf
    • minLength and maxLength

시도 1

접근 방식

  • string, number, boolean은 그대로 반환
  • enum일 경우 해체
  • object일 경우 재귀
  • array일 경우 재귀
  • object의 경우 required, readonly 등 처리

코드

type JSONSchema2TS<T> = T extends { enum: infer E extends readonly any[] }
  ? E[number]
  : T extends { type: "string" }
  ? string
  : T extends { type: "number" }
  ? number
  : T extends { type: "boolean" }
  ? boolean
  : T extends { type: "object" }
  ? T extends { properties: infer P }
    ? T extends { required: readonly (infer R extends string)[] }
      ? {
          [K in Extract<keyof P, R[number]>]: JSONSchema2TS<P[K]>;
        } & {
          [K in Exclude<keyof P, R[number]>]?: JSONSchema2TS<P[K]>;
        }
      : {
          [K in keyof P]?: JSONSchema2TS<P[K]>;
        }
    : Record<string, unknown>
  : T extends { type: "array" }
  ? T extends { items: infer I }
    ? JSONSchema2TS<I>[]
    : unknown[]
  : never;

코드 설명

  • enum 타입일 경우, E[number] 형태로 반환
  • string, number, boolean 타입일 경우 그대로 반환
  • object 타입일 경우, propertiesrequired를 처리, 이후 재귀
  • array 타입일 경우, 재귀로 처리

[medium] 27133. Square

View on GitHub: https://tsch.js.org/27133

문제

Implement the generic type Square<T> which will return the square of the given number.

문제 설명

  • 주어진 숫자의 제곱을 반환하는 문제

시도 1

접근 방식

  • 0이 있을 경우 제외하고 계산(나중에 00으로 계산)
  • 절대값 처리
  • 제곱 길이만큼의 배열 활용

코드

type Abs<N extends number> = `${N}` extends `-${infer R extends number}`
  ? R
  : N;

type SplitZeroes<
  N extends number,
  Z extends string = ""
> = `${N}` extends `${infer N extends number}0`
  ? SplitZeroes<N, `${Z}00`>
  : [N, Z];

type SquareTuple<
  N extends number,
  A extends any[] = [],
  Acc extends any[] = []
> = A["length"] extends N
  ? [...A, ...Acc]
  : SquareTuple<N, [1, ...A], [...A, ...A, ...Acc]>;

type Square<
  _N extends number,
  N extends [number, string] = SplitZeroes<_N>,
  U extends any[] = SquareTuple<Abs<N[0]>>
> = `${U["length"]}${N[1]}` extends `${infer N extends number}` ? N : never;

코드 설명

  • Abs<N[0]> : 절대값 처리
  • SplitZeroes<_N> : 0 제외 처리 (나중에 00 형태로 추가 것임)
  • SquareTuple<Abs<N[0]>> : 제곱 길이만큼의 배열 생성
  • 해당 결과를 바탕으로 조합하여 제곱 결과 반환

[medium] 27152. Triangular Number

View on GitHub: https://tsch.js.org/27152

문제

Implement the generic type Square<T> which will return the square of the given number.

문제 설명

  • 1부터 N까지의 합을 반환하는 문제

시도 1

접근 방식

  • Array를 활용하여 1부터 N까지 증가하는 배열 생성
  • 해당 배열의 길이의 합을 반환하는 로직 생성

코드

type NArr<
  N extends number,
  Result extends unknown[] = []
> = Result["length"] extends N ? Result : NArr<N, [...Result, unknown]>;

type Triangular<
  N extends number,
  FirstArr extends unknown[] = NArr<N>,
  Result extends unknown[] = []
> = FirstArr["length"] extends 0
  ? Result["length"]
  : FirstArr extends [infer _, ...infer Rest]
  ? Triangular<N, Rest, [...Result, ...FirstArr]>
  : never;

코드 설명

  • NArr<N> : 1부터 N까지 증가하는 배열 생성
  • FirstArr : 최초 N의 크기의 배열 생성, 이후 1개씩 요소 삭제
  • Result : FirstArr의 요소의 누적 합 배열

[medium] 27862. Cartesian Product

View on GitHub: https://tsch.js.org/27862

문제

Given 2 sets (unions), return its Cartesian product in a set of tuples.

예시

CartesianProduct<1 | 2, "a" | "b">;
// [1, 'a'] | [2, 'a'] | [1, 'b'] | [2, 'b']

문제 설명

  • 두 개의 집합을 받아 카티시안 곱을 반환하는 문제

시도 1

접근 방식

  • 두 개의 집합을 전체 순회하며 튜플 형태로 반환

코드

type CartesianProduct<T, U, TT = T, UU = U> = T extends TT
  ? U extends UU
    ? [T, U]
    : never
  : never;

코드 설명

  • T extends TT : T의 요소를 하나씩 순회
  • U extends UU : U의 요소를 하나씩 순회
  • [T, U] : 튜플 형태로 반환
  • 순회해서 생긴 튜플들은 |로 구분되어 반환됨

[medium] 27932. Merge All

View on GitHub: https://tsch.js.org/27932

문제

Merge variadic number of types into a new type. If the keys overlap, its values should be merged into an union.

예시

type Foo = { a: 1; b: 2 };
type Bar = { a: 2 };
type Baz = { c: 3 };

type Result = MergeAll<[Foo, Bar, Baz]>; // expected to be { a: 1 | 2; b: 2; c: 3 }

문제 설명

  • 가변 인자의 타입을 하나의 타입으로 병합
  • 키가 겹칠 경우 값을 합치는(union) 문제

시도 1

접근 방식

  • T extends T 꼴로 각 요소를 순회하며 키를 확인
  • 만약에 키가 result에 존재하면 해당 키의 값을 머지
  • 만약에 키가 result에 존재하지 않으면 해당 키의 값을 추가

코드

type MergeAll<XS extends any[], Result = {}> =
  XS extends [infer First, ...infer Rest]
    ? { [Key in keyof Result]: Key extends keyof First ? Result[Key] | First[Key] : Result[Key] }.. 어쩌구
    : Result

실패 이유

  • 조건문이 너무 많이 들어가고, 명확하게 코드 진행이 되지 않는 느낌
  • 다른 방식으로 해결하고자 접근방식 변경

시도 2

접근 방식

  • 기존 Merge 로직 사용
  • T extends [infer First, ...infer Rest] 꼴로 각 요소를 순회하며 키를 확인
  • 해당 요소를 Merge 처리해주고, 이후 재귀로 처리

코드

type Merge<F, S> = {
  [K in keyof F | keyof S]: K extends keyof F
    ? K extends keyof S
      ? F[K] | S[K]
      : F[K]
    : K extends keyof S
    ? S[K]
    : never;
};

type MergeAll<T extends object[], Result = {}> = T extends [
  infer First extends object,
  ...infer Rest extends object[]
]
  ? MergeAll<Rest, Merge<Result, First>>
  : Result;

코드 설명

  • Merge<Result, First> : 현재 요소와 이전 결과를 Merge 처리 (기존에 사용하던 Merge 로직 참고, 단 유니온 처리)
  • MergeAll<Rest, Merge<Result, First>> : 이후 재귀로 처리
  • Result : 최종 결과

[medium] 27958. Check Repeated Tuple

View on GitHub: https://tsch.js.org/27958

문제

Implement type CheckRepeatedChars<T> which will return whether type T contains duplicated member

예시

type CheckRepeatedTuple<[1, 2, 3]>   // false
type CheckRepeatedTuple<[1, 2, 1]>   // true

문제 설명

  • 튜플에 중복된 요소가 있는지 확인하는 문제

시도 1

접근 방식

  • 전체 요소 순회 후, 각 요소를 비교하여 중복된 요소가 있는지 확인

코드

type IsEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
  ? 1
  : 2
  ? true
  : false;

type IsRepeat<T extends unknown[], El, Cnt extends unknown[] = []> = T extends [
  infer First,
  ...infer Rest
]
  ? IsEqual<First, El> extends true
    ? IsRepeat<Rest, El, [...Cnt, unknown]>
    : IsRepeat<Rest, El, Cnt>
  : Cnt["length"] extends 1
  ? false
  : true;

type CheckRepeatedTuple<T extends unknown[]> = T extends [
  infer First,
  ...infer Rest
]
  ? IsRepeat<T, First> extends true
    ? true
    : CheckRepeatedTuple<Rest>
  : false;

코드 설명

  • IsEqual<X, Y> : 두 요소가 같은지 확인
  • IsRepeat<T, First> : 현재 요소와 이전 결과를 비교하여 중복된 요소가 있는지 확인(전체 요소에 존재하는 현재 요소의 개수가 1개인지 확인)
  • CheckRepeatedTuple<T> : 전체 요소를 순회하며 중복된 요소가 있는지 확인, 중복된 요소가 있으면 true, 없으면 다음 요소 확인
profile
세상에 못할 일은 없어!

0개의 댓글