高级类型

150 阅读3分钟

我们可以通过type去声明一个类型别名

  • 接口可以在extendsimplements子句中命名,但对象类型文字的类型别名不能命名。
  • 接口可以有多个合并声明,但对象类型文字的类型别名不能.
  • 一般来说,如果不清楚什么时候用interface/type,能用 interface 实现,就用 interface , 如果不能就用 type
联合类型

联合类型就是将两个类型联合起来,只要两者符合其中一者就可以,用|做连接

type testType=string|number
const test=(x:testType):testType=>x

console.log(test(1))  //1
console.log(test('test'))  //test
console.log(test([1])) //类型“number[]”的参数不能赋给类型“testType”的参数
交叉类型

交叉类型就是类型与类型合并,两个都要符合,用&做连接

interface test1 {
    X: number;
}

interface test2 {
    Y: number;
}

type testType = test1 & test2;
const test = (x: testType): testType => x;
console.log(test({ X: 1, Y: 2 }));
console.log(test({ X: 1})); //类型“{ X: number; }”中缺少属性“Y”
类型保护与区分类型

当我们使用联合类型作为函数的返回值,要使用返回值里的方法会被如果不是两个类型里共有的,会被推断为没有该属性,这是因为ts的类型保护,这种情况我们可以使用类型断言

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // ...
}

let pet = getSmallPet();
pet.layEggs(); // okay
pet.swim(); // error

if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
} else {
    (<Bird>pet).fly();
}
用户自定义的类型保护

要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个 类型谓词

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // ...
}

//自定义类型保护
function isFish(pet: Fish | Bird): pet is Fish {
    return (<Fish>pet).swim !== undefined;
}

let pet = getSmallPet();
if (isFish(pet)) {
    pet.swim();
} else {
    pet.fly();
}

在上面的例子用isFish定义了自定义类型保护,返回值pet is Fish就是类型谓词,TypeScript不仅知道在 if分支里 pet是 Fish类型; 它还清楚在 else分支里,一定 不是 Fish类型,一定是 Bird类型。

字面量类型

我们可以使用字符串作为类型去使用

type state='signIn'|'Logout';

function isSignIn(user:state):boolean{
    return user==='signIn'?true:false
}

数字字面量类型道理也是一样的

可辨识联合

可辨识联合类型概念

  1. 具有普通的单例类型属性— 可辨识的特征
  2. 一个类型别名包含了那些类型的联合— 联合
  3. 此属性上的类型保护。
interface Square { 
    kind: "square";
    size: number;
} 
interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
} 
interface Circle {
    kind: "circle";
    radius: number; 
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) { 
    switch (s.kind) { 
        case "square": return s.size * s.size;
        case "rectangle": return s.height * s.width;
        case "circle": return Math.PI * s.radius ** 2; 
    } 
}
多态的 this类型

多态的this就是会在每个操作之后都会返回this实例

class Num{
    constructor(public val:number){
        this.val=val
    }

    add(x):this{
        this.val+=x
        return this
    }

    minus(x):this{
        this.val-=x
        return this
    }
}

console.log(new Num(1).add(2).minus(1).val) //2
索引类型

可以通过keyof关键字去提取类型中的key

interface Type{
    x:string,
    y:string,
    z:string
}

type X= keyof Type //type X = "x" | "y" | "z"

映射类型
interface Type{
    x:string,
    y:string,
    z:string
}

type Readonly<T>={
    readonly [p in keyof T]: T[p]
}

type X=Readonly<Type> // X = { readonly x: string; readonly y: string; readonly z: string; }

上面的例子我们通过Readonly<T>类型里面通过in关键字便利keyof T里的值,给每一个属性添加上readonly属性

预定义的有条件类型

TypeScript 2.8在lib.d.ts里增加了一些预定义的有条件类型:

  • Exclude<T, U> -- 从T中剔除可以赋值给U的类型。
  • Extract<T, U> -- 提取T中可以赋值给U的类型。
  • NonNullable<T> -- 从T中剔除nullundefined
  • ReturnType<T> -- 获取函数返回值类型。
  • InstanceType<T> -- 获取构造函数类型的实例类型。
type Type="a" | "b" | "c" | "d"
type T01=Exclude<Type,'a'> //"b" | "c" | "d"

type T02=Extract<Type,'a'> //"a"

type T03 = NonNullable<string | number | undefined> //string|number

type T04 = ReturnType<() => string>;//string

function f1(s: string) { return { a: 1, b: s }; }

type T05 = ReturnType< typeof f1> //{ a: 1, b: s }

class C {
    x = 0;
    y = 0;
}

type T06 = InstanceType<typeof C>; // C