type Chainable<T = {}> = {
option<K extends PropertyKey, V>(key: K extends keyof T ? never : K, value: V): Chainable<Omit<T, K> & { [P in K]: V }>
get(): {
[P in keyof T]: T[P]
}
}
Solution by LovePlayCode #37851
interface Chainable<T extends object = {}> {
option<K extends string, V>(key: K, value: V): Chainable<T & {[P in K]: V}>;
get(): T;
}
Solution by pkutsenko #37823
type Chainable<T = {}> = {
option<K extends string, V>(
key: K extends keyof T ? never : K,
value: K extends keyof T ? (V extends T[K] ? V : never) : V
): Chainable<Omit<T, K> & { [P in K]: V }>
get(): T
}
Solution by AlexanderNP #37808
type Chainable<T = object> = { option: <K extends PropertyKey,V>(key: K,value: V) => Chainable<T & Record<K,V>>; get: () => T; }
Solution by jjojae9393 #37635
// your answers
type Chainable<T = {}> = { option<K extends string, V>(key: K, value: V): Chainable<T & { [P in K]: V }> get(): T }
Solution by PAVANT009 #37604
type Chainable<T = {}> = {
option<K extends string, V>(key: K, value: V): Chainable<Omit<T, K> & Record<K, V>>;
get(): T;
}
/* _____________ Test Cases _____________ */
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')
.option('name', 'last name')
.get()
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
}
Solution by AnastasiaSv #37416
// your answers
Solution by AnastasiaSv #37415
逐步推演:
type Chainable = {
option(key: string, value: any): any;
get(): any;
}
R, get() 返回 Rtype Chainable<R = object> = {
option(key: string, value: any): any;
get(): R;
}
option() 链式调用返回 Chainabletype Chainable<R = object> = {
option(key: string, value: any): Chainable;
get(): R;
}
option<K, V>() 定义泛型 K, V;Chainable 泛型叠加类型声明type Chainable<R = object> = {
option<K extends string, V>(
key: K,
value: V
): Chainable<R & Record<K, V>>;
get(): R;
}
type Chainable<R = object> = {
option<K extends string, V>(
key: Exclude<K, keyof R>,
value: V
): Chainable<R & Record<K, V>>;
get(): R;
}
Omit<R, K>type Chainable<R = object> = {
option<K extends string, V>(
key: Exclude<K, keyof R>,
value: V
): Chainable<Omit<R, K> & Record<K, V>>;
get(): R;
}
Solution by djdidi #37146
// 여기 풀이를 입력하세요
type Chainable<Props = {}> = {
option<K extends string, T>(key: K, value: T): Chainable<Omit<Props, K> & { [key in K]: T }>;
get(): Props
}
Solution by seungdeok #36734
type Chainable<T = {}> = { option<K extends string, V>( key: K, value: V ): Chainable<T & { [P in K]: V }> get(): T }
Solution by ChemieAi #36564
type Chainable<T = {}> = {
option<K extends string, V>(key: K extends keyof T
? never
: K, value: V)
: Chainable<Omit<T, K> & Record<K, V>>
get(): T
}
Solution by gakki-san #36438
type Chainable<T = {}> = {
option<K extends keyof any,R>(
key: K extends keyof T
? R extends T[K]
? never : K
: K, value: R
): Chainable<Omit<T,K> & Record<K,R>>
get(): T
}
Solution by gakki-san #36431
type Chainable<T = {}> = { option<K extends string, V>( key: K, value: V ): Chainable<T & { [P in K]: V }>
get(): T }
Solution by asylbekduldiev #36404
type Chainable<CurrentConfig = {}> = {
option<OptionKey extends string, OptionValue>(
key: Exclude<OptionKey, keyof CurrentConfig>,
value: OptionValue
): Chainable<Omit<CurrentConfig, OptionKey> & Record<OptionKey, OptionValue>>;
get(): CurrentConfig;
};
Solution by AleksandrShcherbackov #36161
type Chainable<T extends Record<keyof any, unknown> = {}> = {
option<K extends keyof any, V>(
key: K,
value: V
): K extends keyof T
? Chainable<Omit<T, K> & Record<K, V>>
: Chainable<Record<K, V> & T>
get: () => T
}
Solution by Shunii85 #36041
type Chainable<R = {}> = {
option<K extends string, V = any>(
key: K extends keyof R ? never: K,
value: V
): Chainable<Omit<R, K> & Record<K, V>>
get(): R
}
Solution by user-9902 #36007
type Chainable<T = {}> = {
option: <K extends string, V>(key: K extends keyof T ? never : K, value: V) => Chainable<Omit<T, K> & Record<K, V>>;
get: () => T
}
explain:
declare const a: Chainable
const result1 = a
.option('foo', 123)
.option('bar', { value: 'Hello World' })
.option('name', 'type-challenges')
.get()
we can find, a.option() can continue calling option or get, so we can kown option should return Chainable type, So
First, wo can add
type Chainable = {
option: (key:string, value: any) => Chainable;
get: any
}
Second, we need a generic parameter T to store type before the option call, and anthoer generic parameter K to avoid keys conflict, so we can get the code
type Chainable<T = {}> = {
option: <K extends string, V>(key: K extends keyof T ? never : K, value: V) => Chainable<Omit<T, K> & Record<K, V>>;
get: any
}
Thrid, we add get return type
type Chainable<T = {}> = {
option: <K extends string, V>(key: K extends keyof T ? never : K, value: V) => Chainable<Omit<T, K> & Record<K, V>>;
get: T
}
Solution by vaclock #35764
type Chainable<T = {}> = {
option<K extends string, V>(
key: K extends keyof T ? never : K,
value: V
): Chainable<Omit<T, K> & Record<K, V>>;
get(): T;
};
Solution by gangnamssal #35554
// 你的答案
// ============= Test Cases =============
import type { Alike, Expect } from "./test-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;
};
// ============= Your Code Here =============
type Chainable<T = {}> = {
option<Key extends string, Value>(
key: Key extends keyof T ? never : Key,
value: Value
): Chainable<{
[k in Key | keyof T]: k extends keyof T
? k extends Key
? Value
: T[k]
: Value;
}>;
get(): T;
};
Solution by run-nan #35476
type Chainable<T = {}> = {
option: <K extends PropertyKey, V>(
key: K extends keyof T ? never : K,
value: V
) => Chainable<Omit<T, K> & Record<K, V>>;
get: () => T;
};
Solution by RanungPark #35453
type Chainable<T = {}> = {
option<K extends string|number, V extends unknown>(
key: K extends keyof T
? V extends T[K]
? never
: K
: K,
value: V
): Chainable<Omit<T, K> & { [P in K]: V }>;
get(): T;
};
Solution by HrOkiG2 #35280
type Chainable<R = unknown> = {
option<T extends string, V extends any>(key: T extends keyof R ? never : T, value: V): Chainable<Omit<R, T> & Record<T, V>>
get(): R
}
Solution by eunsukimme #35121
type Chainable<T = {}> = {
option<K extends string, V>(key: K, value: V): Chainable<Omit<T, K> & Record<K, V>>;
get(): T;
};
Solution by 2njeong #35083
type Chainable<T = {}> = {
option<K extends string, V>(key: string, value: any): Chainable<T & {[P in K]: V}>
get(): T
}
Solution by raeyoung-kim #35013
// 你的答案
type Chainable<T = {}> = {
option<K extends string, V>(key: K extends keyof T ? never : K, value: V): Chainable<{
[P in K]: V
} & {
[P in keyof T as P extends K ? never : P]: T[P]
}>
get(): T
}
Solution by heyuelan #34689
declare const config: Chainable<Result>
interface Result {
foo: number
name: string
bar: {
value: string
}
}
type Chainable<T> = {
options: <Key extends keyof T>(key: Key, val: T[Key]) => Chainable<Omit<T, Key>>
get: () => T
}
const result = config.options('foo', 12)
.options('name', 'foo')
.options('bar', { value: 'bar' })
.get()
Solution by semet #34645
type Chainable<T extends Record<string, any> = {}> = {
option<K extends string, V extends any>(key: K extends keyof T ? never : K, value: V ): K extends keyof T ? Chainable<{ [P in K]: V }> : Chainable<T & { [P in K]: V }>
get(): T
}
// your answers
Solution by Rustamaha #34597
type Chainable<T = {}> = {
option: <K extends string, V>(key: K extends keyof T ? never
: K, value: V) => Chainable<Omit<T, K> & Record<K, V>>
get: () => T
}
Solution by devshinthant #34564
type Chainable<T = {}> = {
option<K extends PropertyKey, V>(
key: K extends keyof T ? never : K, value: V
): Chainable<Omit<T, K> & {[P in K]: V}>
get(): {
[P in keyof T]: T[P]
}
}
Solution by ktim816 #34434
type Chainable<T extends Record<string, any> = {}> = {
option: <K extends string, V>(key: K extends keyof T ? never : K, value: V) => K extends keyof T ? Chainable<Omit<T, K> & Record<K, V>> : Chainable<T & Record<K, V>>
get: () => T
}
Solution by rookie-luochao #34391