/*
  12 - Chainable Options
  -------
  by Anthony Fu (@antfu) #medium #application
  
  ### Question
  
  Chainable options are commonly used in Javascript. But when we switch to TypeScript, can you properly type it?
  
  In this challenge, you need to type an object or a class - whatever you like - to provide two function `option(key, value)` and `get()`. In `option`, you can extend the the current config type by the given key and value. We should about to access the final result via `get`.
  
  For example
  
  ```ts
  declare const config: Chainable
  
  const result = config
    .option('foo', 123)
    .option('name', 'type-challenges')
    .option('bar', { value: 'Hello World' })
    .get()
  
  // expect the type of result to be:
  interface Result {
    foo: number
    name: string
    bar: {
      value: string
    }
  }

You don't need to write any js/ts logic to handle the problem - just in type level.

You can assume that key only accept string and the value and be anything - just leave it as-is. Same key won't be passed twice.

View on GitHub: https://tsch.js.org/12 */

/* _____________ Your Code Here _____________ */

type Chainable = { option(key: string, value: any): any get(): any }

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

declare const a: Chainable

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

type cases = [ Expect<Alike<typeof result, Expected>> ]

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

/* _____________ Further Steps _____________ / /

Share your solutions: https://tsch.js.org/12/answer View solutions: https://tsch.js.org/12/solutions More Challenges: https://tsch.js.org */


Chainable 이라는 타입을 만들어야 하는데 이 타입은 option 이라는 메소드로 키, 밸류를 받아서 get 메소드를 실행하면 만들어진 객체를 리턴하는 타입이다.

답은

```tsx
type Chainable<T = {}> = {
  option<K extends string, V>(key: K, value: V): Chainable<T & { [P in K]: V }>
  get(): {
    [k in keyof T]: T[k]
  }
}

어려웠다.... 그래서 답안지 봤다...

Chainable<T & { K: V }>

키를 매핑타입으로 꺼내 주어야 했다.

Chainable<T & { [k in K]: V }>

사실 잘 이해가 안 가긴 한다.

테스트 해보자.

테스트1

type A1<K extends string, V, T = {}> = T & { K: V }