美文网首页
TypeScript基础二(联合类型、对象类型)

TypeScript基础二(联合类型、对象类型)

作者: 柠檬不萌5120 | 来源:发表于2019-01-28 14:53 被阅读0次

    联合类型

    联合类型(Union Types)表示取值可以为多种类型中的一种。中途可以改变数据类型,只要在规定的数据类型中就可以。

    let myFavoriteNumber: string | number;
    myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;
    
    // 报错
    let myFavoriteNumber: string | number;
    myFavoriteNumber = true;
    

    联合类型使用 | 分隔每个类型。

    这里的 let myFavoriteNumber: string | number 的含义是,允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型。
    注意:

    • 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
    function getLength(something: string | number): number {
        return something.length;
    }
    
    // index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
    //   Property 'length' does not exist on type 'number'.
    

    上例中,length 不是 string 和 number 的共有属性,所以会报错。访问 string 和 number 的共有属性是没问题的:

    function getString(something: string | number): string {
        return something.toString();
    }
    

    联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:

    let myFavoriteNumber: string | number;
    myFavoriteNumber = 'seven';
    console.log(myFavoriteNumber.length); // 5
    myFavoriteNumber = 7;
    console.log(myFavoriteNumber.length); // 编译时报错
    

    上例中,第二行的 myFavoriteNumber 被推断成了 string,访问它的 length 属性不会报错。

    而第四行的 myFavoriteNumber 被推断成了 number,访问它的 length 属性时就报错了。

    对象类型-接口(interface)

    在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。接口一般首字母大写。

    interface Person {
        name: string;
        age: number;
    }
    
    let tom: Person = {
        name: 'Tom',
        age: 25
    };
    

    上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 tom,它的类型是 Person。这样,我们就约束了 tom 的形状必须和接口 Person 一致。少一些属性,多一些属性都是不允许的。

    //报错 少一些属性
    let tom: Person = {
        name: 'Tom'
    };
    //报错 多一些属性
    let tom: Person = {
        name: 'Tom',
        age: 25,
        gender: 'male'
    };
    
    • 可选属性 在属性后边加?
    interface Person {
        name: string;
        age?: number;
    }
    //不会报错
    let tom: Person = {
        name: 'Tom'
    };
    //不会报错
    let tom: Person = {
        name: 'Tom',
        age:25
    };
    //报错
    let tom: Person = {
        name: 'Tom',
        age: 25,
        gender: 'male'
    };
    

    可选属性的含义是该属性可以不存在。但添加未定义的属性仍然是不允许的。这也是上面报错代码报错的原因。

    • 任意属性 [propName: string]

    有时候我们希望一个接口允许有任意的属性,可以使用如下方式:

    interface Person {
        name: string;
        age?: number;
        [propName: string]: any;
    }
    
    let tom: Person = {
        name: 'Tom',
        gender: 'male'
    };
    

    需要注意的是,一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性:

    interface Person {
        name: string;
        age?: number;
        [propName: string]: string;
    }
    
    let tom: Person = {
        name: 'Tom',
        age: 25,
        gender: 'male'
    };
    
    // index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
    // index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
    //   Index signatures are incompatible.
    //     Type 'string | number' is not assignable to type 'string'.
    //       Type 'number' is not assignable to type 'string'.
    

    上例中,任意属性是string类型,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了。

    • 只读属性 readonly

    有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:

    interface Person {
        readonly id: number;
        name: string;
        age?: number;
        [propName: string]: any;
    }
    
    let tom: Person = {
        id: 89757,
        name: 'Tom',
        gender: 'male'
    };
    
    tom.id = 9527;
    
    // index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
    

    上例中,使用 readonly 定义的属性 id 初始化后,又被赋值了,所以报错了。
    注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:

    interface Person {
        readonly id: number;
        name: string;
        age?: number;
        [propName: string]: any;
    }
    
    let tom: Person = {
        name: 'Tom',
        gender: 'male'
    };
    
    tom.id = 89757;
    
    // index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
    //   Property 'id' is missing in type '{ name: string; gender: string; }'.
    // index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
    

    上例中,报错信息有两处,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。

    第二处是在给 tom.id 赋值的时候,由于它是只读属性,所以报错了。

    相关文章

      网友评论

          本文标题:TypeScript基础二(联合类型、对象类型)

          本文链接:https://www.haomeiwen.com/subject/xqyvjqtx.html