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作一个索引类型,把对象类型变成联合类型,就获得了咱们想要的那些成员名称。

相关文章
相关标签/搜索