zoukankan      html  css  js  c++  java
  • TypeScript 对象的类型-接口

    一、什么是接口

    在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型

    接口是一系列抽象方法的声明,是一些方法特征的集合,第三方可以通过这组抽象方法调用,让具体的类执行具体的方法

    TypeScript 中接口除了可用于对类的一部分行为进行抽象以外,还可用于对「对象的形状(Shape)」进行描述

    举个例子:

    interface Person {
        name: string;
        age: number;
    }
    
    let faker: Person = {
        name: 'Faker',
        age: 25
    };

    这里定义了一个接口 Person,接着定义了一个变量 Faker,它的类型是 Person。这样就约束了 faker 的形状必须和接口 Person 一致

    注意:接口一般首字母大写

    定义的变量比接口少了一些属性是不允许的:

    interface Person {
        name: string;
        age: number;
    }
    
    let faker: Person = {
        name: 'faker'
    };
    
    // index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
    //   Property 'age' is missing in type '{ name: string; }'.

    多一些属性也是不允许的:

    interface Person {
        name: string;
        age: number;
    }
    
    let faker: Person = {
        name: 'faker',
        age: 25,
        gender: 'male'
    };
    
    // index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
    //   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

    因此赋值时变量的形状必须和接口的形状保持一致

    二、可选属性

    可选属性是指该属性可以不存在,当我们希望不要完全匹配一个形状,可以用可选属性:

    interface Person {
        name: string;
        age?: number;
    }
    
    let faker: Person = {
        name: 'Faker'
    };
    interface Person {
        name: string;
        age?: number;
    }
    
    let faker: Person = {
        name: 'Faker',
        age: 25
    };

    这时仍然不允许添加未定义的属性:

    interface Person {
        name: string;
        age?: number;
    }
    
    let faker: Person = {
        name: 'Faker',
        age: 25,
        gender: 'male'
    };
    
    // examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
    //   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

    三、任意属性

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

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

    使用 [propName: string] 定义了任意属性取 string 类型的值

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

    interface Person {
        name: string;
        age?: number;
        [propName: string]: string;
    }
    
    let faker: Person = {
        name: 'Faker',
        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 的子属性,所以报错了

    注意:一个接口中只能定义一个任意属性

    如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:

    interface Person {
        name: string;
        age?: number;
        [propName: string]: string | number;
    }
    
    let faker: Person = {
        name: 'Faker',
        age: 25,
        gender: 'male'
    };

    四、只读属性

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

    interface Person {
        readonly id: number;
        name: string;
        age?: number;
        [propName: string]: any;
    }
    
    let faker: Person = {
        id: 89757,
        name: 'Faker',
        gender: 'male'
    };
    
    faker.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 faker: Person = {
        name: 'Faker',
        gender: 'male'
    };
    
    faker.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.

    上例中,报错信息有两处:

    1、在对 faker 进行赋值的时候,没有给 id 赋值

    2、在给 faker.id 赋值的时候,由于它是只读属性,所以报错了

    五、联合类型和接口

    以下实例演示了如何在接口中使用联合类型:

    interface Person { 
        name:string; 
        words:string[]|string|(()=>string); 
    } 
     
    // words 是字符串
    let faker:Person = {name:"Faker",words:"Hello"}; 
    console.log(faker.words)  
     
    // words 是字符串数组
    faker = {name:"Faker",words:["Hello","World"]}; 
    console.log(faker.words[0]); 
    console.log(faker.words[1]);  
     
    // words 是一个函数表达式
    faker = {name:"Faker",words:()=>{return "**Hello World**";}}; 
     
    let fn:any = faker.words; 
    console.log(fn());

    输出结果为:

    Hello
    Hello
    World
    **Hello World**

    六、接口和数组

    接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串

    interface Names { 
       [index:number]:string 
    } 
     
    let list1:Names = ["Faker",1,"Bang"] // 错误元素 1 不是 string 类型
    
    interface Ages { 
       [index:string]:number 
    } 
     
    let list2:Ages; 
    list2["Faker"] = 22  // 正确 
    list2[2] = "ten"     // 错误

    七、接口继承

    接口继承就是说接口可以通过其他接口来扩展自己,Typescript 允许接口继承多个接口,继承使用关键字 extends

     

    1、单接口继承

    单接口继承语法格式:

    Child_interface_name extends super_interface_name

    示例:

    interface Person { 
       age:number 
    } 
     
    interface Musician extends Person { 
       instrument:string 
    } 
     
    let faker = <Musician>{}; 
    faker.age = 22 
    faker.instrument = "piano" 
    console.log("年龄: " + faker.age)
    console.log("喜欢的乐器: " + faker.instrument)

    输出:

    年龄: 22
    喜欢的乐器: piano

    2、多接口继承

    多接口继承语法格式:

    Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name

    示例:

    interface IParent1 { 
      v1:number 
    } 
     
    interface IParent2 { 
      v2:number 
    } 
     
    interface Child extends IParent1, IParent2 { } 
    let faker:Child = { v1:22, v2:23} 
    console.log("value 1: " + faker.v1 + " value 2: " + faker.v2)

    输出:

    value 1: 22 value 2: 23

  • 相关阅读:
    奥数视频
    提车应该检查哪?4S店都怕你检查这4个“雷区”,别等后悔才知道
    乒乓球拍子和套胶选择
    2018天津英华国际学校初中报名指南
    水瓶座出生日期是几月几号到几月几号
    乒乓球 世锦赛
    鸡蛋羹要怎么蒸才会更嫩?秘诀在这里
    家庭理财方法:知道这7个定律可以帮你赚更多钱!
    要知道股市有“三底”,估值底、政策底、市场底!
    DbMigration使用方法
  • 原文地址:https://www.cnblogs.com/Leophen/p/13269772.html
Copyright © 2011-2022 走看看