[英]Typescript Conditional Types Not Figuring Out Type
假設給定類型:
export declare type MongoManagerFilter<T> = {
[P in keyof T]?: (P extends keyof T ? T[P] : any);
};
嘗試指定過濾器時:
update.$setOnInsert.createdAt = new Date();
我收到此錯誤:
Type 'Date' is not assignable to type '"createdAt" extends keyof T ? T[keyof T & "createdAt"] : any'.ts(2322)
但是,如果我將過濾器更改為此它可以工作:
export declare type MongoManagerFilter<T> = {
[P in keyof T]?: any;
};
為什么條件語句實際上並沒有弄清楚類型? 它只是將代碼保留為類型。
我知道過濾器沒有意義,我有另一種類型而不是keyof T
來捕獲點表示法,但是我遇到了同樣的問題,條件語句無法確定實際類型。
interface CollectionDocument {
_id?: string;
createdAt: Date;
}
type PathImpl<T, Key extends keyof T> =
Key extends string
? T[Key] extends Record<string, any>
? `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof Date | keyof Object | keyof string> & string>}`
| `${Key}.${Exclude<keyof T[Key], keyof Date | keyof Object | keyof string> & string}`
: never
: never;
type Path<T> = keyof T | PathImpl<T, keyof T>;
type PathValue<T, P extends Path<T>> =
P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: P extends keyof T
? T[P]
: any;
export declare type MongoManagerFilter<T> = {
[P in Path<T>]?: PathValue<T, P>;
};
export class MongoManagerCollection<T extends CollectionDocument> {
constructor() {}
updateOne(filter: MongoManagerFilter<T>) {
// THIS DOES NOT WORK
filter._id = '';
filter.createdAt = new Date();
}
}
// THIS WORKS
let testModel = new MongoManagerCollection<CollectionDocument>();
testModel.updateOne({_id: 'test', createdAt: new Date()});
通用類型T
在:
export class MongoManagerCollection<T extends CollectionDocument> {
constructor() { }
updateOne(filter: MongoManagerFilter<T>) {
// THIS DOES NOT WORK
filter._id = '';
filter.createdAt = new Date();
}
}
是一個黑匣子。 filter._id
被解析為非評估條件類型。 將其視為非稱為 function。 從未調用過的 Function 不返回任何值。 filter._id
也是如此。 filter._id
對應於此:
type PathValue<T, P extends Path<T>> =
P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: P extends keyof T ////////////////////////////////////////////////
? T[P] // Property is resolved as a conditional type //
: any; ///////////////////////////////////////////////
您可能已經注意到, filter._id
是P extends keyof T? T[P]: any
P extends keyof T? T[P]: any
而不僅僅是T[P]
。
有一種解決方法。 您可以使用T[P & keyof T]
代替conditional type
。 請參閱工作示例:
interface CollectionDocument {
_id?: string;
createdAt: Date;
}
type PathImpl<T, Key extends keyof T> =
Key extends string
? T[Key] extends Record<string, any>
? `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof Date | keyof Object | keyof string> & string>}`
| `${Key}.${Exclude<keyof T[Key], keyof Date | keyof Object | keyof string> & string}`
: never
: never;
type Path<T> = keyof T | PathImpl<T, keyof T>;
type PathValue<T, P extends Path<T>> =
P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: T[P & keyof T]
export declare type MongoManagerFilter<T> = {
[P in Path<T>]?: PathValue<T, P>;
};
export class MongoManagerCollection<T extends CollectionDocument> {
constructor() { }
updateOne(filter: MongoManagerFilter<T>) {
filter._id = ''; // ok
filter.createdAt = new Date(); // ok
filter.createdAt = 'sdf'; // expected error
}
}
// THIS WORKS
let testModel = new MongoManagerCollection<CollectionDocument>();
testModel.updateOne({ _id: 'test', createdAt: new Date() });
如果您對path
實現感興趣,可以查看此答案、 此實用程序和/或我的文章。
我不知道 MongoDB api 和你的類型的要求,所以我不能說它們是否需要修改。
此外,您可以擺脫泛型:
export class MongoManagerCollection {
constructor() { }
updateOne(filter: MongoManagerFilter<CollectionDocument>) {
filter._id = ''; // ok
filter.createdAt = new Date(); // ok
}
}
// THIS WORKS
let testModel = new MongoManagerCollection();
testModel.updateOne({ _id: 'test', createdAt: new Date() });
但我不認為這是你想要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.