[Typescript challenge] 20. Medium - Chainable Options
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 current config type by the given key and value. We should about to access the final result via get
.
For example
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 accepts string
and the value
can be anything - just leave it as-is. Same key
won't be passed twice.
Solution:
type Chainable<T = {}> = {
option<K extends string, V>(key: K extends keyof T ? (V extends T[K] ? never: K): K, value: V): Chainable<Omit<T, K> & {[P in K]: V}>,
get(): T
}
Test case:
/* _____________ Test Cases _____________ */
import type { Alike, Expect } from '@type-challenges/utils'
type x = 'a' extends 'a' ? true: false
declare const a: Chainable
const result1 = a
.option('foo', 123)
.option('bar', { value: 'Hello World' })
.option('name', 'type-challenges')
.get()
// If key is the same, and value is the same type
// then should expect error
const result2 = a
.option('name', 'another name')
// @ts-expect-error
.option('name', 'last name')
.get()
// If key is the same, but value is different type
// then should override the value with the same key
const result3 = a
.option('name', 'another name')
.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
}
Notice Test 2:
// If key is the same, and value is the same type
// then should expect error
const result2 = a
.option('name', 'another name')
// @ts-expect-error
.option('name', 'last name')
.get()
This means, we need to control key's type:
key: K extends keyof T ? (V extends T[K] ? never: K): K
if K is already inside T, then check V is the same type of T[K], if they are the same type, should be never, otherwise keep K.// If key is the same, but value is different type
// then should override the value with the same key
const result3 = a
.option('name', 'another name')
.option('name', 123)
.get()
type Expected3 = {
name: number
}
The finial output is number type. Which means should override previous type.
Chainable<Omit<T, K> & {[P in K]: V}>
If you don't omit previous type, then it should be
{
name: string
} & {
name: number
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2020-09-08 [CSS 3] content-visibility: auto Improve rendering performance
2020-09-08 [Machine Learning] Neural Networks: Representation Quiz
2018-09-08 [GraphQL] Query Local and Remote Data in Apollo Link State
2018-09-08 [Spring Boot ] Creating the Spring Boot Project : Demo: Creating a REST Controller
2018-09-08 [Web Analytics] Into to Web Analytics
2016-09-08 [AngularJS] Test an Angular Component with $componentController
2016-09-08 [AngularJS] Isolate State Mutations in Angular Components