• Typescript 实战 --- (3)接口


    接口可以用来约束对象、函数以及类的结构和类型,这是一种代码协作的契约,调用该接口时必须遵守,不能改变
     
    ts与其它语言不同的是,并没有 “实现” 接口这个概念,而是只关注值的外形,只要传入的对象满足上面的必要条件,那么它就是被允许的。这就是所谓的“鸭式辩型法”(像鸭子一样走路、游泳和嘎嘎叫的鸟就是鸭子)
     
    1、对象类型接口
     
    interface List {
      id: number;
      name: string;
    }
    
    interface Result {
      data: List[];
    }
    
    function getResult(result: Result) {
      result.data.forEach(item => {
        console.log(item.id, item.name);
      })
    }
    
    let myResult = {
      data: [
        {id: 1, name: 'Bob', score: 98}, 
        {id: 2, name: 'Carl', score: 87}
      ] 
    };
    
    getResult(myResult);
    
    // 1 'Bob'
    // 2 'Carl'
     
    类型检查器会查看 getResult 的调用,其传入的参数中包含了三个属性,但是编译器只会检查那些必需的属性是否存在,并且其类型是否匹配
     
    然而,有些时候ts却并不会这么宽松,例如:getResult 参数传入的是对象字面量,ts就会对额外的参数进行类型检查
    getResult({ data: [{id: 1, name: 'Bob', score: 98}, {id: 2, name: 'Carl', score: 87}] });
    
    
    // error TS2322: Type '{ id: number; name: string; score: number; }' is not assignable to type 'List'.
    // Object literal may only specify known properties, and 'score' does not exist in type 'List'.
     
    绕过这种检查的方法有四种:
      (1)、把对象字面量赋值给一个变量(如前面的例子中的变量 myResult)
      (2)、使用类型断言
      (3)、可选属性:带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号
      (4)、字符串索引签名
     
    // 使用类型断言
    getResult({data: [{id: 1, name: 'Bob'}, {id: 2, name: 'Carl', score: 98}]} as Result)
    
    // 可选属性
    interface List {
      id: number;
      name: string;
      score?: number;  // 可选属性
    }
    
    // 字符串索引签名
    interface List {
      id: number;
      name: string;
      [propName: string]: any; // 字符串索引签名
    }
    
    getResult({ 
      data: [{id: 1, name: 'Bob', score: 98}, {id: 2, name: 'Carl', score: 87}] 
    });
    
    
    // 1 'Bob'
    // 2 'Carl'
     
    1-1、可索引类型
    可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。比如:a[0] 或 a["name"]
    索引签名可以是字符串和数字,也可以同时使用两种类型的索引
     
    // 数字索引
    interface StringArray {
      [inder: number]: string;
    }
    
    let s1: StringArray = ["TypeScript", "Webpack"];
    console.log('s1: ', s1);   // s1:  [ 'TypeScript', 'Webpack' ]
    
    // 字符串索引
    interface ScoreMap {
      [subject: string]: number;
    }
    
    let s2: ScoreMap = {
      "Chinese": 99,
      "Math": 100
    }
    console.log('s2: ', s2);   // s2:  { Chinese: 99, Math: 100 }
    
    // 同时使用字符串和数字索引
    interface StudentMap {
      [index: number]: string;
      [name: string]: string;
    } 
    
    let s3: StudentMap[] = [
      {
        1: "678分",
        "姓名": "张伟"
      },
      {
        2: "670分",
        "姓名": "尔康"
      }
    ]
    console.log('s3: ', s3);
    // s3:  [ { '1': '678分', '姓名': '张伟' }, { '2': '670分', '姓名': '尔康' } ]
     
    注意:如果同时使用字符串索引和数字索引,数字索引的返回值必须是字符串索引返回值类型的子类型。因为当使用number来索引时,js会将它隐式转换成string,然后再去索引对象。
     
    class Animal {
      name: string;
    }
    
    class Dog extends Animal {
      breed: string;
    }
    
    interface Okay {
      [x: string]: Animal;
      [y: number]: Dog;
    }
    
    // Numeric index type 'Animal' is not assignable to string index type 'Dog'.
    interface NotOkay {
      [x: string]: Dog;
      [y: number]: Animal;  // 数字索引类型“Animal”不能赋给字符串索引类型“Dog”
    }

    1-2、只读属性

    可以在属性名前用 readonly 来指定只读属性

    interface Point {
      readonly x: number;
      readonly y: number;
    }
    
    // 可以通过赋值一个对象字面量来构造一个Point。 赋值后,x和y再也不能被改变了。
    let p: Point = { x: 3, y: 5};
    console.log('p', p);   // p { x: 3, y: 5 }
    
    // p.x = 20;   // Cannot assign to 'x' because it is a read-only property

    ts 具有 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法都去掉了。可以确保数组创建后就再也不能修改

    let arr: number[] = [1, 2, 3];
    let ro: ReadonlyArray<number> = arr;
    
    ro[0] = 33;   // 类型“readonly number[]”中的索引签名仅允许读取
    ro.push(4);   // 类型“readonly number[]”上不存在属性“push”
    ro.length = 99;  // Cannot assign to 'length' because it is a read-only property

    判断该使用readonly 还是 const 的方法主要是看作为变量还是作为属性,作为变量的话使用 const,作为属性则使用 readonly

    2、函数类型接口

    它就像是一个只有 参数列表 和 返回值类型 的函数定义,参数列表里的每个参数都需要名字和类型
    interface Add {
      (base: number, increment: number): number
    }
    
    // 调用接口
    let add: Add = (x: number, y: number) => x + y;
    console.log( add(1, 2) );   // 3
    3、类类型接口
     
    ts中的类可以像Java里的接口一样,使用类来实现一个接口,由此来明确的强制一个类去符合某种契约。
    interface ClockInterface {
      currentTime: Date;
    }
    
    class Clock implements ClockInterface {
      currentTime: Date;
      constructor(h: number, m: number) {}
    }
     
    也可以在接口中描述一个方法,在类里实现它
    interface ClockInterface {
      currentTime: Date;
      setTime(d: Date):
    }
    
    class Clock implements ClockInterface {
      currentTime: Date;
      setTime(d: Date) {
        this.currentTime = d;
      }
      constructor(h: number, m: number) {}
    }
    4、混合类型接口
     
    同时使用 对象类型接口 和 函数类型接口
    interface Lib {
      (): void;
      version: string;
      doSomething(): void;
    }
    
    function getLib() {
      let lib = (() => {}) as Lib;
      lib.version = '0.01';
      lib.doSomething = () => console.log('hello world!');
      return lib;
    }
    
    let l1 = getLib();
    console.log( l1() );  // undefined
    
    let l2 = getLib();
    l2.doSomething();     // hello world!
     
    5、继承接口
     
    接口也可以相互继承,可以从一个接口里复制成员到另一个接口里,由此可以更加灵活的将接口分割到可重用的模块里
    interface Shape {
      color: string;
    }
    
    interface Square extends Shape {
      sideLength: number;
    }
    
    let square: Square = {
      color: 'red',
      sideLength: 15
    }
    
    console.log('square ', square);   // square  { color: 'red', sideLength: 15 }
     
    一个接口可以继承多个接口,创建出多个接口的合成接口
    interface Shape {
      color: string;
    }
    
    interface PenStroke {
      penWidth: number
    }
    
    interface Square extends Shape, PenStroke {
      sideLength: number;
    }
    
    let square: Square = {
      color: 'red',
      penWidth: 6,
      sideLength: 15
    }
    
    console.log('square ', square);   // square  { color: 'red', penWidth: 6, sideLength: 15 }
     
  • 相关阅读:
    010editor爆破与注册机
    [FlareOn4]notepad
    [FlareOn6]Snake(NES逆向)
    [FlareOn6]Memecat Battlestation
    [FlareOn6]FlareBear
    回车符和换行符之间的区别
    docker配置搭建elasticsearch集群
    docker部署安装harbor
    ansible的get_url模块
    ansible的lineinfile与blockinfile模块
  • 原文地址:https://www.cnblogs.com/rogerwu/p/12188357.html
Copyright © 2020-2023  润新知