1. 云栖社区>
  2. JavaScript教程>
  3. 正文

TypeScript入门-高级类型

作者:用户 来源:互联网 时间:2017-11-30 13:08:55

osconstantsmingwandroid mp3解码mysqlthinkphpphp

TypeScript入门-高级类型 - 摘要: 本文讲的是TypeScript入门-高级类型, 高级类型交叉类型交叉类型,就是将多个类型合并为一个新的类型,这个新的类型具有这多个类型的成员,含有这几个类型的所有特性,是他们的综合体,像是集合的并集 例子: function extend<T,U>(first: T, se

高级类型交叉类型

交叉类型,就是将多个类型合并为一个新的类型,这个新的类型具有这多个类型的成员,含有这几个类型的所有特性,是他们的综合体,像是集合的并集

例子:

function extend<T,U>(first: T, second: U): T&U {    let result = <T & U>{};    for (let id in first) {        (<any>result)[id] = first[id];    }    for (let id in second) {        if (!result.hasOwnProperty(id)) {            (<any>result)[id] = second[id];        }    }    return result;}class Person {    constructor(public name: string) {    }}interface Loggable {    log(): void;}class myLoggable implements Loggable {    log() {        console.log('qwe');    }}let jim = extend(new Person('qq'), new myLoggable());console.log(jim.name);jim.log();

例子中jim有Person中的name属性也有myLoggable中的log()方法

联合类型

联合类型,不像是交叉类型是多个类型的合集,表示是这多个类型中的一种类型,像是集合中的交集,只有多个类型中共有的特性才可以被调用

例如要向一个函数传递参数,这个参数可能是number也可能是string

function padLeft(value: string, padding: any) {    if (typeof padding === "number") {        return Array(padding + 1).join(" ") + value;    }    if (typeof padding === "string") {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}padLeft("Hello world", 4); // "    Hello world"

这里存在一个问题,将padding定义为any,表示我们可以传递任何值给padding,这个错误TypeScript是不会报错的,只有在编译时才会报错

解决这个问题,可以采用联合类型,用竖线分割每个类型,表示是这几个类型中的一种

function padLeft(value: string, padding: string | number) {    ........}let f = padLeft("Hello world", true); // error

如果一个值是联合类型,就只能访问这多个类型所共有的成员

interface Bird {    fly();    layEggs();}interface Fish {    swim();    layEggs();}function getSmallPet(): Fish | Bird {    ...}let pet = getSmallPet();pet.layEggs(); // okaypet.swim();    // errors

getSmallPet的返回类型就是一个联合类型,所以pet就只能访问Bird和Fish的共有成员layEggs()

在上面的例子中,我们不知道pet到底是那种类型,所以就不可能去访问哪些不是公共的成员,如果我们知道了pet的类型,就可以访问该类型的所有成员了

类型保护和区分类型

为了解决上面提到的具体类型的确定问题,需要引入类型断言(类型转换)

let pet = getSmallPet();if ((<Fish>pet).swim) {    (<Fish>pet).swim();} else {    (<Bird>pet).fly();}

问题显而易见,每次都需要对pet进行类型转换,麻烦

用户自定义的类型保护

类型保护就可以解决上述每次都要进行类型断言的缺点,类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。 要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个类型断言

function isFish(pet: Fish | Bird): pet is Fish {    return (<Fish>pet).swim !== undefined;}

pet is Fish就是类型断言。 一个断言是 parameterName is Type这种形式,parameterName必须是来自于当前函数签名里的一个参数名。

// 'swim' 和 'fly' 调用都没有问题了if (isFish(pet)) {    pet.swim();}else {    pet.fly();}

TypeScript不仅知道在if里是Fish,而且还知道在else里是Bird类型

 

typeof类型保护

我们将之前的padLeft代码改用类型断言来实现

function isNumber(x: any): x is number {    return typeof x === "number";}function isString(x: any): x is string {    return typeof x === "string";}function padLeft(value: string, padding: string | number) {    if (isNumber(padding)) {        return Array(padding + 1).join(" ") + value;    }    if (isString(padding)) {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}

如果要按这样写就要为每个原始类型写一个函数,麻烦。TypeScript会把"typeof v === typeofname"和"typeof v !== typeofname"看做是类型保护,所以就不必为一个原始类型写一个函数,直接用typeof就可以了

function padLeft(value: string, padding: string | number) {    if (typeof padding === "number") {        return Array(padding + 1).join(" ") + value;    }    if (typeof padding === "string") {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}
instanceof类型保护

instanceof类型保护是通过构造函数来细化类型的一种方式

interface Padder {    getPaddingString(): string}class SpaceRepeatingPadder implements Padder {    constructor(private numSpaces: number) { }    getPaddingString() {        return Array(this.numSpaces + 1).join(" ");    }}class StringPadder implements Padder {    constructor(private value: string) { }    getPaddingString() {        return this.value;    }}function getRandomPadder() {    return Math.random() < 0.5 ?        new SpaceRepeatingPadder(4) :        new StringPadder("  ");}// 类型为SpaceRepeatingPadder | StringPadderlet padder: Padder = getRandomPadder();if (padder instanceof SpaceRepeatingPadder) {    padder; // 类型细化为'SpaceRepeatingPadder'}if (padder instanceof StringPadder) {    padder; // 类型细化为'StringPadder'}
类型别名

类型别名就是给类型起一个别名,而且可以用于基础的数据类型

type Name = string;type NameResolver = () => string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name {    if (typeof n === 'string') {        return n;    }    else {        return n();    }}

与接口不同,类型别名不会新建一个类型,只是类型的名字变了而已

type Alias = { num: number }interface Interface {    num: number;}declare function aliased(arg: Alias): Alias;declare function interfaced(arg: Interface): Interface;

在上面的代码中interfaced返回值的类型是Interface,而aliased返回值的类型是对象字面量

类型别名与接口还有一个地方不同的是类型别名不可以被extends和implements

上面说了类型别名与接口的两个不同点,当然也有相同点,即都可以使用泛型

type Tree<T> = {    value: T;    left: Tree<T>;    right: Tree<T>;}
字符串字面量类型

字符串字面量类型可以与联合类型,类型保护和类型别名很好的配合

type Easing = "ease-in" | "ease-out" | "ease-in-out";class UIElement {    animate(dx: number, dy: number, easing: Easing) {        if (easing === "ease-in") {            // ...        }        else if (easing === "ease-out") {        }        else if (easing === "ease-in-out") {        }        else {            // error! should not pass null or undefined.        }    }}let button = new UIElement();button.animate(0, 0, "ease-in");button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here

只能从规定的三种类型中选择一种类型进行传递,其他的类型会报错

可辨识联合

可以合并字符串字面量类型,联合类型,类型保护和类型别名来创建一个叫做可辨识联合的高级模式

先定义三个将要联合的接口,每个接口都有kind属性,但是值不同,king属性可以作为可辨识的特征和标识

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;    }}

注意:如果在Shape中添加新的类型,那么在switch下也要添加相应的判断

参考资料:

TypeScript中文网 · TypeScript——JavaScript的超集

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索osconstants , mingw , android mp3解码 mysqlthinkphpphp ,以便于您获取更多的相关知识。

弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率

40+云计算产品,6个月免费体验

现在注册,免费体验40+云产品,及域名优惠!

云服务器9.9元/月,大学必备