본문 바로가기
Language/Typescript

타입챌린지 : 3196-Flip Arguments (medium)

by hsloth 2023. 5. 26.

 

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

 

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

 

함수의 인자를 뒤집어서 리턴하는 타입이다.

예를들면 

function (a: string, b: number, c: boolean) 을 function (a: boolean, b:number, c: string) 으로 말이다.

이때까지 함수에 대해 타입을 많이 구현해보지 않아서 조금 헤맸지만, 그래도 할만하다.

type Push<T, U> = T extends any[] ? [...T, U] : never;

type FlipArguments<T extends (...args:any) => any, U extends any[] = []> = 
	T extends (...args: infer F) => infer R ? 
	F extends [...infer O, infer L] ? 
	FlipArguments<(...args: O) => R, Push<U, L>> : (...args: U) => R : never;

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

type cases = [
  Expect<Equal<FlipArguments<() => boolean>, () => boolean>>,
  Expect<Equal<FlipArguments<(foo: string) => number>, (foo: string) => number>>,
  Expect<Equal<FlipArguments<(arg0: string, arg1: number, arg2: boolean) => void>, (arg0: boolean, arg1: number, arg2: string) => void>>,
]

type errors = [
  // @ts-expect-error
  FlipArguments<'string'>,
  // @ts-expect-error
  FlipArguments<{ key: 'value' }>,
  // @ts-expect-error
  FlipArguments<['apple', 'banana', 100, { a: 1 }]>,
  // @ts-expect-error
  FlipArguments<null | undefined>,
]

 

일단, Push 타입을 만들어 배열 맨 뒤에 인자를 Push가능하게 해주었다.

type FlipArguments<T extends (...args:any) => any, U extends any[] = []> : FlipArguments라는 타입을 정의하고, T는 여러 인자를 가진 함수라고 정의한다. 그리고 U는 빈 배열을 기본 값으로 가진다.

T extends (...args: infer F) => infer R ? : T가 F를 타입으로 갖는 인자들을 가지고, 리턴 타입이 R일 때,

F extends [...infer O, infer L] ? : F에서 마지막 인자인 L를 뽑아서

FlipArguments<(...args: O) => R, Push<U, L>> : 재귀를 하는데, 재귀시 T의 위치에는 나머지 인자 O를 가지고 리턴값이 R인 함수가 들어가고, U의 위치에는 원래 U에 L를 push한 배열이 들어간다.

(...args: U) => R : never : 그리고 재귀가 끝나면 T에서 인자가 뒤집인 배열인 U를 인자로하고 리턴값이 R인 함수를 반환한다.