接口可以用来约束对象、函数以及类的结构和类型

typescript并没有 “实现” 接口这个概念,而是只关注值的外形,只要传入的对象满足上面的必要条件,那么它就是被允许的。

对象类型接口



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 的调用,其传入的参数中包含了三个属性,但是编译器只会检查那些必需的属性是否存在,且其类型是否匹配。所以即使多了一个score属性,也是可以通过编译的。

但是当 getResult 参数传入的是对象字面量,ts不仅会检查必要的属性,还会对额外的参数进行类型检查。




text 类型索引_typescript索引类型


除了把对象字面量赋值给一个变量外,还有3种方法绕过这种检查:

  1. 使用类型断言
  2. 可选属性:在属性名字后面加一个?符号
  3. 字符串索引签名
// 使用类型断言
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'


索引类型

可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。比如:a[0] 或 a["name"]

定义格式:


interface 接口名 {
  [任意字段: 索引类型]: 索引返回值类型;
}


索引签名可以是字符串和数字,也可以同时使用两种类型的索引


// 数字索引
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”
}


只读属性

可以在属性名前用 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


typescript 具有 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

函数类型接口

接口还可以用来限制函数的 参数列表 和 返回值类型 。


interface Add {
  (base: number, increment: number): number
}

// 调用接口
let add: Add = (x: number, y: number) => x + y;
console.log( add(1, 2) );   // 3


类类型接口

typescript 中的类可以像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) {}
}


混合类型接口

可以同时使用 对象类型接口 和 函数类型接口


interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

var c: Counter;
c(10);
c.reset();
c.interval = 5.0;


继承接口

接口也可以相互继承,可以从一个接口里复制成员到另一个接口里,由此可以更加灵活的将接口分割到可重用的模块里


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 }


摘抄自Typescript 实战 --- (3)接口