typescript的never
類型表明永不存在的值的類型,它只能被賦值爲never
。html
任意類型與never
交叉都獲得never
:typescript
type T1 = number & never; // never
type T2 = string & never; // never
複製代碼
能夠這樣理解:若type T = T1 & T2
,則T
類型的值能夠賦給T1
或T2
類型的變量(相似類的繼承關係)。 那麼若與never
交叉,則T
類型的值能夠賦給一個never
類型的變量,那T
只能是never
了。bash
任意類型與never
聯合不受影響:ide
type T1 = number | never; // number
type T2 = string | never; // string
複製代碼
理解與上述交叉類型狀況相似: 若type T = T1 | T2
,則T1
或T2
類型的值能夠賦給T
類型的變量。 因爲never
類型能夠賦給任意變量,天然對聯合類型不產生影響了。ui
typescript的keyof
關鍵字,將一個類型映射爲它全部成員名稱的聯合類型。如typescript官網上的示例:idea
interface Person {
name: string;
age: number;
location: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string
複製代碼
keyof實際給咱們一個操做聯合類型的途徑。結合typescript的其餘feature,如類型映射與索引類型,咱們得以在對象類型與聯合類型之間遊刃有餘地轉換,爲工程中更多變量找到最適合的類型歸屬。spa
咱們看一個來自這裏的例子:code
type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never })[T];
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
複製代碼
下面一行不用過多解釋了,在T類型中除去成員名在K中的成員。而上面一行代碼特別有意思,也特別難看懂,它所作的是對於T與U兩個字符串字面量類型,從T中除去包含在U中的那些字符串:htm
type A = Diff<"a" | "b" | "c", "a">; // "b" | "c"
type B = Diff<"a" | "b" | "c", "b" | "d">; // "a" | "c"
複製代碼
它是如何作到的呢?咱們首先看它的前面部分:對象
type FirstHalf<T extends string, U extends string> = { [P in T]: P } & { [P in U]: never }
type C = FirstHalf<"a" | "b" | "c", "b" | "d">;
// {
// "a": "a",
// "b": "b",
// "c": "c"
// } & {
// "b": never,
// "d": never
// }
複製代碼
咱們再將type C
作逐成員的交叉:
type C = {
"a": "a",
"b": "b" & never,
"c": "c",
"d": never
}
複製代碼
任意類型與never
交叉的結果都是never
,所以
type C = {
"a": "a",
"b": never,
"c": "c",
"d": never
}
複製代碼
咱們再看Diff
類型:
type B = Diff<"a" | "b" | "c", "b" | "d">;
= {
"a": "a",
"b": never,
"c": "c",
"d": never
}["a" | "b" | "c"];
= "a" | never | "c";
= "a" | "c";
複製代碼
這樣就達到了前文所述的目的。
咱們試圖移除一個object type
中全部類型爲never
的成員。能夠這樣操做:
type OmitNever<T> = Pick<T, {[P in keyof T]: T[P] extends never ? never : P}[keyof T]>;
type T = {
a: string,
b: never,
c: string,
}
type T1 = OmitNever<T>; // { a: string, c: string }
複製代碼
原理相似第一個例子。咱們試圖把T
中全部非never
成員的名稱找出,從T
中pick
出來。因此先弄一個對象類型出來:
type OmitNeverHalf<T> = {[P in keyof T]: T[P] extends never ? never : P}
type TT = OmitNeverHalf<T>;
// {
// "a": "a",
// "b": never,
// "c": "c"
// }
複製代碼
再用keyof T
作一個索引類型,把對象類型變成聯合類型,就獲得了咱們想要的那些成員名稱。