讓我在這個例子中解釋我的想法。假設我有這門課:
class Class1 {
f1!: string;
f2!: string;
f3!: number;
f4!: Date;
}
如果我需要一個包含該型別別成員的型別string。我可以做例如
type Class1Stings = Omit<Class1, 'f3' | 'f4'>;
但我需要知道確切的屬性名稱。我想要這樣的東西:
type Class1Stings = KeepOnlyTypes<Class1, string>;
// or
type Class1Stings = RemoveTypes<Class1, number | Date>;
這可能嗎?
=============編輯:
我的游樂場鏈接
uj5u.com熱心網友回復:
這有點棘手,但您可以通過首先找到這些屬性的鍵(使用我在此處選擇的技巧),然后Pick按照您的指示使用。
type PickStringProps<Source extends object> = Pick<Source, {
[Key in keyof Source]: Source[Key] extends string ? Key : never;
}[keyof Source]>;
// Usage:
class Class1 {
f1!: string;
f2!: string;
f3!: number;
f4!: Date;
}
type Class1Strings = PickStringProps<Class1>;
// ^?
游樂場鏈接(以下說明。)
或者,這是一個可重用的通用版本:
// A type that picks out the keys for properties from `Source` that are
// assignable to `PickType`
type KeysByType<Source extends object, PickType> = {
[Key in keyof Source]: Source[Key] extends PickType ? Key : never;
}[keyof Source];
// A type that picks the properties from `Source` that are assignable to `Picktype`
type PickByType<Source extends object, PickType> =
Pick<Source, KeysByType<Source, PickType>>;
(我們可以將上述兩者結合起來,但這更清楚一些。)
用法:
class Class1 {
f1!: string;
f2!: string;
f3!: number;
f4!: Date;
}
type Class1Strings = PickByType<Class1, string>;
// ^?```
游樂場鏈接
復制我的回答here,這里是如何KeysByType作業的——它有兩個部分:
該
{/*...*/}部分將 的每個屬性Source映射到一個新的映射型別,其中屬性的型別是鍵本身或never. 假設我們有:type Example = { a: string; b: string; c: number; };KeysByType<Example, string>只是創建這個匿名型別的第一部分:{ a: "a"; b: "b"; c: never; }然后最后的
[keyof Source]部分創建這些屬性的型別的聯合,理論上應該是"a" | "b" | never,但never總是從聯合型別中洗掉,所以我們最終得到-具有陣列型別的屬性"a" | "b"的鍵。Example
然后創建PickByType,我們Pick按照您的指示使用。
在評論中,您問為什么這似乎在這里不起作用:
function assignDates<T extends Class1>(
obj: T,
source: Record<KeysByType<T, Date>, string> | undefined,
keys: KeysByType<T, Date>[]
): void {
if (source) {
for (const key of keys) {
if (source[key] !== undefined) {
obj[key] = new Date(source[key]);
// ^^??? Type 'Date' is not assignable to type 'T[KeysByType<T, Date>]'.(2322)
}
}
}
}
(請注意,我已經從您的原始版本中更新了一點:我將名稱更改為json,source因為它的值不是 JSON [那將是一個字串],并修復了型別,因此您不需要as anyon source[key]:它的值是字串,而不是日期,從代碼來看,它似乎是可選的。)
答案是:它正在作業,但該assignDates函式不是型別安全的,因為雖然Class1可能只有Date屬性(特別是),但它的子類可以將它們細化為 aaDate子型別:
class MyDate extends Date {
myNiftyMethod() { /*...*/ }
}
class Class2 extends Class1 {
f4: MyDate;
// ...
}
Class2適合型別約束extends Class1,因此您可以將其傳遞給assignDates,但f4不再只是a Date,而是 a MyDate,因此您不能將 a 分配Date給它。
當然,非泛型版本也assignDate有同樣的Class2問題,但不會引發obj[key]分配錯誤。我希望這是 TypeScript 的某種限制。
鑒于非通用版本沒有錯誤,您可能只是告訴 TypeScript 忽略該錯誤,但您可能想發布一個問題(因為我們與您在此處提出的原始問題相距甚遠)詢問是否有一種方法可以以型別安全的方式撰寫通用版本。(如果你這樣做,請在下面的評論中鏈接到它;我有興趣看到答案。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/462377.html
標籤:打字稿
上一篇:TypeScript地圖:鍵入'number|undefined'不可分配給型別'number'
下一篇:通用高階函式引數型別
