我的previous question关于TypeScript是什么开始了这个主题. 在上一个问题中,我想创建一个通用的sort()
方法,它将与排序键数组一起工作,由您在这里看到的SortKey
类型定义. 在上述问题中得到的结果只适用于该类型的直接性质.
现在,我想继续这个过程,看看我是否可以使它递归,以便我可以指定嵌套对象的键. 这就是我的工作:
type Comparer<T> = (a: T, b: T) => number;
type KeyPath<T, TParentKey = undefined> = {
[K in keyof T]: K extends string ? (TParentKey extends undefined ? `${K}` : `${TParentKey & string}.${K}`) : never;
}[keyof T]
| {
[K in keyof T]: T[K] extends object ? K extends string ? KeyPath<T[K], TParentKey extends undefined ? `${K}` : `${TParentKey & string}.${K}`> : never : never;
}[keyof T]
;
type ValueAtPath<T, Path> = Path extends keyof T
? T[Path]
: Path extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? ValueAtPath<T[Key], Rest>
: never
: never;
type Getter<T, K extends string> = (model: T, key: K) => ValueAtPath<T,K>;
// This type is not working and is the subject for this question:
type SortKey<TModel> = {
[K in KeyPath<TModel>]: {
key: K;
order: 'asc' | 'desc';
getter: Getter<TModel, K>;
comparer: Comparer<ValueAtPath<TModel, K>>;
}
}[KeyPath<TModel>];
那么,我怎么知道SortKey
个里面使用的"个体类型"有效呢? 像这样:
// Let's define a couple of data models.
type User = {
id: number;
name: {
first: string;
last: string;
};
emails?: string[];
isActive: boolean;
type: 'customer' | 'support'
};
type Domain = {
id: number;
value: string;
user: User;
};
// Now let's start testing the TS types.
type TestKey = KeyPath<Domain>;
// Visual Studio Code shows in Intellisense the following for the above type:
type TestKey = "id" | "value" | "user" | KeyPath<User, "user">
// Although unsure why it did not expand the recursion, Intellisense fully works on a variable:
const k: TestKey = 'user.name'; // <-- See picture 1.
// This also seems OK as per the Intellisense tooltip:
type TestValue = ValueAtPath<Domain, 'user.name.last'>;
// The tooltip reads it is string, which is the data type of the `last` nested property:
type TestValue = string
// Now testing Comparer:
const comp: Comparer<ValueAtPath<Domain, 'user.name'>> = (a, b) => 0;
// Intellisense shows:
const comp: Comparer<{
first: string;
last: string;
}>
// Finally, testing Getter:
const getter: Getter<Domain, 'user.name.first'> = m => m.user.name.first;
// Intellisense works perfectly on the parameter variable "m".
好吧,所以人们会认为,扩展到type DomainSortKey = SortKey<Domain>
会工作. 但事实并非如此 TypeScript说DomainSortKey === unknown
百万美元的问题是:在Jebus发生了什么?