typescript 接口

157 阅读4分钟

interface

接口:为类型命名,可以用来描述对象类型和函数类型 接口作用:检查必须的属性是否存在及类型是否正确(无关顺序)

interface LabelledValue { // 有一个 label属性且类型为string的对象
  label: string;
}

function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}

let myObj =<LabelledValue > {size: 10, label: "Size 10 Object"}; // 对象可以有接口没定义的其他属性,但无法在代码中引用
myObj.no = 'no' // 已经初始化的对象不能手动添加接口中没有的属性
printLabel(myObj);

接口定义包含属性的对象类型

可选属性

通过在属性名字后面加一个?符号定义一个可选属性 作用:

  1. 对可能存在的属性进行预定义
  2. 捕获引用了不存在的属性时的错误

只读属性

只能在对象刚创建时设定值的属性,通过在属性名前面readonly来定义

实例: typescript中的ReadonlyArray类型

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

readonly vs const

该用readonly还是const? 做为变量使用的话用 const,做为属性则使用readonly。

对象字面量--额外的属性检查

interface SquareConfig {
  color?: string;
  width: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
  let newSquare = {color: "white", area: 100};
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}

let obj = { width: 100, colour: "black", size: 10}
let mySquare = createSquare(obj);
let squareObj = createSquare({ width: 100, colour: "black", size: 10}) // 对象字面量会进行额外的属性检查

对象字面量在被赋值给变量或作为函数参数传递时,会被特殊对待进行额外属性检查: 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误。

跳过额外属性检查

  1. 使用类型断言
  2. 为接口定义添加字符串索引签名,前提是能够确定这个对象可能具有某些做为特殊用途使用的额外属性。
interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}
  1. 将对象字面量赋值给一个变量

接口定义函数类型

通过接口来描述函数类型,需要给接口一个调用签名,类似一个只有参数列表和返回值类型的函数声明。参数列表中每个参数都需要有名称和类型

interface SearchFunc {
  (source: string, subString: string): boolean;
}

定义之后就可以像使用对象类型一样使用函数类型

let mySearch: SearchFunc = function(source: string, subString: string) {
  let result = source.search(subString);
  return result > -1;
}

函数的参数会被逐个进行检查,不要求参数名称一样,但是参数类型需要兼容。如果没有指定参数类型,则会使用推断类型,函数返回值也会使用推断类型。

接口定义可索引类型

为对象类型添加索引签名描述对象索引的类型与相应的索引返回值类型

interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

接口成员是实例属性

构造函数是特殊的静态函数,其作用是返回一个实例本身。所以构造器作为接口的一部分是没有意义的,因为接口的成员都是实例相关的。

接口继承

接口继承接口

接口可以相互继承, 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。

接口可以单继承,也可以多继承

interface Shape {
    color: string;
}
interface PenStroke {
    penWidth: number;
}
interface Square extends Shape, PenStroke {
    sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

接口继承类

当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 接口会继承到类的private和protected成员。 注意: 当一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现。

class Control {
    private state: any;
}
interface SelectableControl extends Control {
    select(): void;
}
class Button extends Control implements SelectableControl {
    select() { }
}
class TextBox extends Control {
    select() { }
}
class Image implements SelectableControl { // 错误:“Image”类型缺少“state”属性。
    select() { }
}

参考

stackoverflow.com/questions/3…

class定义中的类型必须有construnctor且成员必须有初始化器