我試圖更好地了解extendsTypeScript中的關鍵字及其潛在應用。
有一件事我所遇到的兩個內置實用工具,Extract并且Exclude是同時利用extends和條件打字。
/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;
/**
* Extract from T those types that are assignable to U
*/
type Extract<T, U> = T extends U ? T : never;
我正在玩弄以更好地理解這種“縮小”是如何作業的,或者更好地說明“子集過濾”是如何作業的,并嘗試創建我自己的實作只是為了查看它的實際效果,并且遇到了這種非常奇怪的行為:
鏈接到游樂場示例:
type ValueSet = string | 'lol' | 0 | {a: 1} | number[] | 643;
type CustomExclude<T, U> = T extends U ? T : never;
// this works:
// type Result1 = 0 | 643
type Result1 = CustomExclude<ValueSet, number>;
// but this doesn't?
// type Result2 = never
type Result2 = ValueSet extends number ? ValueSet : never;
為什么會這樣?
我希望兩個實體都能回傳正確的型別子集,但條件型別僅在通過泛型表達時才有效。
有人可以向我解釋這背后的邏輯嗎?
uj5u.com熱心網友回復:
第二段代碼進行了一次檢查,以查看整個型別是否從 number 擴展。如果是,則回傳整個型別,否則回傳never。帶有泛型的版本將遍歷聯合中的所有單個型別(首先string,然后"lol",然后0等)并單獨評估它們。然后,您將獲得幸存下來的任何個體型別的聯合。
可以從您的第二個示例中獲得一個非從不值,但前提是每個可能的值都是一個數字。例如:
type Example = 1 | 3 | 5;
type Example2 = Example extends number ? Example : never;
// Example2 is 1 | 3 | 5
uj5u.com熱心網友回復:
請參閱分配條件型別:
當條件型別作用于泛型型別時,當給定聯合型別時,它們會變成分布式的。例如,采取以下措施:
type ToArray<Type> = Type extends any ? Type[] : never;
如果我們將聯合型別插入 ToArray,則條件型別將應用于該聯合的每個成員。
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]
因此,如果您使用extends泛型型別,則整個條件型別適用于聯合中的每個元素。
如果您使用extends非泛型型別,就像您在第二個示例中使用的那樣,條件型別適用于整個型別。
您甚至可以在第一個示例中關閉分配。只需將您的泛型包裝在方括號中:
type ValueSet = string | 'lol' | 0 | {a: 1} | number[] | 643;
type CustomExclude<T, U> = [T] extends [U] ? T : never;
// never
type Result1 = CustomExclude<ValueSet, number>;
包裹在方括號中的泛型被視為非泛型型別,就像在您的第一個示例中一樣。
在實踐中,這種模式非常有用。通常T extends any僅用于打開分配。
假設您有一些物件型別。您想獲取所有鍵并對其應用一些修改器。換句話說,映射它們。考慮這個例子:
type Foo = {
name: string;
age: number
}
// non verbose approach, distributivity
type ChangeKey<T> = keyof T extends string ? `${keyof T}-updated` : never
type Result = ChangeKey<Foo>
// middle verbose approach
type ChangeKey1<T> = {
[Prop in keyof T]: Prop extends string ? `${Prop}-updated` : never
}[keyof T]
type Result1 = ChangeKey1<Foo>
// verbose approach
type ChangeKey2<T extends Record<string, unknown>> = keyof {
[Prop in keyof T as Prop extends string ? `${Prop}-updated` : never]: never
}
type Result2 = ChangeKey2<Foo>
您可能已經注意到,ChangeKey比其他人更優雅。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/334823.html
