typescript:never與keyof的妙用

never類型

typescript的never類型表明永不存在的值的類型,它只能被賦值爲neverhtml

任意類型與never交叉都獲得nevertypescript

type T1 = number & never;   // never
type T2 = string & never;   // never
複製代碼

能夠這樣理解:若type T = T1 & T2,則T類型的值能夠賦給T1T2類型的變量(相似類的繼承關係)。 那麼若與never交叉,則T類型的值能夠賦給一個never類型的變量,那T只能是never了。bash

任意類型與never聯合不受影響:ide

type T1 = number | never;   // number
type T2 = string | never;   // string
複製代碼

理解與上述交叉類型狀況相似: 若type T = T1 | T2,則T1T2類型的值能夠賦給T類型的變量。 因爲never類型能夠賦給任意變量,天然對聯合類型不產生影響了。ui

keyof

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

應用

Diff Type

咱們看一個來自這裏的例子: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";
複製代碼

這樣就達到了前文所述的目的。

去除全部never成員

咱們試圖移除一個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成員的名稱找出,從Tpick出來。因此先弄一個對象類型出來:

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作一個索引類型,把對象類型變成聯合類型,就獲得了咱們想要的那些成員名稱。

相關文章
相關標籤/搜索