-
Notifications
You must be signed in to change notification settings - Fork 391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
「重学TS 2.0 」TS 练习题第三十题 #49
Comments
declare const config: Chainable
type Simplify<T> = {
[P in keyof T]: T[P]
}
type Chainable<T = {}> = {
// S extends string can make S is Template Literal Types
option<V, S extends string>(key: S, value: V): Chainable<T & {
// use Key Remapping in Mapped Types generate { S: V } type https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#key-remapping-in-mapped-types
[P in keyof {
S: S,
} as `${S}`]: V
}>
get(): Simplify<T>
}
const result = config
.option('age', 7)
.option('name', 'lolo')
.option('address', { value: 'XiaMen' })
.get()
type ResultType = typeof result
|
个人觉得这道题主要是要发现, config 可以进行链式调用, 这样可以很容易的联想到 js 中的 关于如何动态命名 key, 可以看一下官方介绍 // 给基础类型 T 增加 { K, V } 键值对
type ReudceType<K extends string, V extends any, T = {}> = T & { [key in [K] as `${K}`]: V }
type Chainable<T = {}> = {
option<K extends string, V extends any>(key: K, value: V): Chainable<ReudceType<K, V, T>>
get(): { [K in keyof T]: T[K] } // 这里也可以直接返回 T, 不过这样并不直观, 所以手动遍历一下
}
// 测试用例
const result = config
.option('age', 7)
.option('name', 'lolo')
.option('address', { value: 'XiaMen' })
.get()
type ResultType = typeof result |
type Chainable<R = {}> = {
option<K extends string | number | symbol, V> (key: K, value: V): Chainable<R & Record<K, V>>
get (): R
} |
declare const config: Chainable
type ITypes = string | number | symbol;
type Chainable<T = {}> = {
option<K extends ITypes, V extends any>(key: K, value: V): Chainable<T & Record<K, V>>;
get(): T;
}
const result = config
.option('age', 7)
.option('name', 'lolo')
.option('address', { value: 'XiaMen' })
.get()
type ResultType = typeof result
const t: ResultType = {
age: 30,
name: 'hello',
address: {
value: 'Huizhou'
}
}
console.log(t);
// 期望 ResultType 的类型是:
// {
// age: number
// name: string
// address: {
// value: string
// }
// } 思路: 链式操作的思维 |
|
declare const config: Chainable;
type Chainable<T0 = {}> = {
option<T, U>(key: keyof T, value: U): Chainable<T0 & { [P in keyof T]: U }>;
get(): T0;
};
const result = config.option("age", 7).option("name", "lolo").option("address", { value: "XiaMen" }).get();
type ResultType = typeof result;
// 期望 ResultType 的类型是:
// {
// age: number
// name: string
// address: {
// value: string
// }
// } |
declare const config: Chainable
type Chainable<T = {}> = {
option<K extends keyof any, V>(key: K, value: V): Chainable<T & {[P in K]: V}>;
get(): T;
}
const result = config
.option('age', 7)
.option('name', 'lolo')
.option('address', { value: 'XiaMen' })
.get()
type ResultType = typeof result |
已经有一样的了🤣 declare const config: Chainable;
type Chainable<T = {}> = {
option<K extends string, V extends any>(key: K, value: V): Chainable<{ [P in K]: V } & T>;
get(): T;
};
const result = config.option("age", 7).option("name", "lolo").option("address", { value: "XiaMen" }).get();
type ResultType = typeof result; |
type Chainable<T = {}> = {
option<K extends PropertyKey, V = unknown>(
key: K,
value: V
): Chainable<
{
[X in keyof T | K]: X extends K ? V : X extends keyof T ? T[X] : never;
}
>;
get(): T;
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
完善
Chainable
类型的定义,使得 TS 能成功推断出result
变量的类型。调用option
方法之后会不断扩展当前对象的类型,使得调用get
方法后能获取正确的类型。The text was updated successfully, but these errors were encountered: