bh2980.dev

12 - Chainable Options

  • #Type Challenges
  • #TypeScript

질문

체인 가능 옵션은 일반적으로 Javascript에서 사용됩니다. 하지만 TypeScript로 전환하면 제대로 구현할 수 있나요?

이 챌린지에서는 option(key, value)get() 두가지 함수를 제공하는 객체(또는 클래스) 타입을 구현해야 합니다. 현재 타입을 option으로 지정된 키와 값으로 확장할 수 있고 get으로 최종 결과를 가져올 수 있어야 합니다.

declare const config: Chainable

const result = config
  .option('foo', 123)
  .option('name', 'type-challenges')
  .option('bar', { value: 'Hello World' })
  .get()

// 결과는 다음과 같습니다:
interface Result {
  foo: number
  name: string
  bar: {
    value: string
  }
}

// !collapse(1:50) collapsed
/* _____________ 테스트 케이스 _____________ */
import type { Alike, Expect } from '@type-challenges/utils'

declare const a: Chainable

const result1 = a
  .option('foo', 123)
  .option('bar', { value: 'Hello World' })
  .option('name', 'type-challenges')
  .get()

const result2 = a
  .option('name', 'another name')
  // @ts-expect-error
  .option('name', 'last name')
  .get()

const result3 = a
  .option('name', 'another name')
  // @ts-expect-error
  .option('name', 123)
  .get()

type cases = [
  Expect<Alike<typeof result1, Expected1>>,
  Expect<Alike<typeof result2, Expected2>>,
  Expect<Alike<typeof result3, Expected3>>,
]

type Expected1 = {
  foo: number
  bar: {
    value: string
  }
  name: string
}

type Expected2 = {
  name: string
}

type Expected3 = {
  name: number
}

문제를 해결하기 위해 js/ts 로직을 작성할 필요는 없습니다. 단지 타입 수준입니다.

keystring만 허용하고 value는 무엇이든 될 수 있다고 가정합니다. 같은 key는 다시 전달할 수 없습니다.

선행 지식

  1. 메서드 타입 정의 방법

    type Example = {
     test(): any\n}
    
     // or
     
     type Example = {
       test: () => any
     }

    메서드는 위처럼 2가지 형태로 타입을 정의할 수 있다.

  2. 타입 스크립트에서 에러 내기

    타입 시스템은 런타임이 아니므로 throw new Error() 같은 방식으로 에러를 낼 수 없다. 대신 타입이 성립하지 않도록 만들어 컴파일 타임 에러를 유도한다.

    가장 자주 쓰는 방식은 특정 인자의 타입을 never로 만들어 호출을 막는 것이다.

풀이