导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

基本介绍

TypeScript 的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。

在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义约束。

(function (){
	// 描述一个对象的类型
	type myType = {
		name: string,
		age: number
	};
	const obj: myType = {
		name: 'sss',
		age: 111
	}
	/*
	*	接口用来定义一个类的结构
	*/
	interface myType2 = {
		name: string,
		age: number
	};
	const obj: myType2 = {
		name: 'www',
		age: 222
	}
})

function printLabel(labelledObj: { label: string }) {
  console.log(labelledObj.label);	// "Size 10 Object"
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
分析:
1. printLabel() 有一个参数,并要求这个对象参数有一个名为`label` 类型为`string`的属性
2. 我们传入的对象参数实际上会包含很多属性(比如:size),但是编译器只会检查那些必需的属性(label)是否存在,并且其类型是否匹配
3. 类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以
interface LabelledValue {
	label: string;
}
function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
分析:
1. `LabelledValue` 接口就好比一个名字,用来描述示例 1 里的要求
2. 它代表了有一个 `label`属性且类型为`string`的对象
3. 只要传入的对象满足`LabelledValue`的必要条件,那么它就是被允许的

可选属性(?:)

接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在

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

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

  let mySquare = createSquare({color: "black"});
  let mySquare2 = createSquare({color: "red", width: 10});
  // let mySquare3 = createSquare({color: "black", width: 10, height: 10}); // 报错:SquareConfig不存在height属性
  console.log(mySquare)	// {color: 'black', area: 33}
  console.log(mySquare2)// {color: 'red', area: 100}

只读属性(readonly)

interface Point {
  readonly x: number;
  readonly y: number;
}
let p1: Point = { x: 10, y: 20 }; // 定义一个对象并赋值
p1.x = 5; // error!
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!

// 以下写法不报错
a = []; // 将一个数组赋值给a,此时a = []
a = ro as number[]; // 使用类型断言重写,此时a = [1, 2, 3, 4]

readonly vs const

额外的属性检查

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

function createSquare(config: SquareConfig) {
    // ...
}

let mySquare = createSquare({color: "black", width: 10, height: 10});
// 报错:SquareConfig不存在height属性
// 方法一:使用类型断言
let mySquare = createSquare({color: "black", width: 10, height: 10} as SquareConfig);
// 方法二:添加一个字符串索引签名
interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}
// 方法三:将这个对象赋值给一个另一个变量
let squareOptions = {color: "black", width: 10, height: 10};
let mySquare = createSquare(squareOptions);

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

函数类型

接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型

interface Add {
  (a: number, b: number): number
}
let add:Add  = (a,b) => a+b
console.log(add(1,2))

对于函数检测的参数名可以与接口中检测的参数名不一致,但是数据类型必须一致

interface Add {
  (num1: number, num2: number): number
}
let add:Add  = (a,b)=>a+b
console.log(add(1,2))

类的类型

使用 implements 来绑定接口interface

interface PersonConstructor {
  new (name: string, age: number): PersonInterface; // 实例部分的interface
}
interface PersonInterface {
  position: string;                 // 静态部分的interface
  setDate(d: Date): any;
}
let createConstructor = (ctor:PersonConstructor, name: string, age: number): PersonInterface =>{
  return new ctor(name, age);
}
class Person implements PersonInterface{
  position = '成都';
  constructor(name: string, age: number){}
  setDate(d: Date){
    console.log(d)
  }
}
let mySkey = createConstructor(Person, 'mySkey', 23);
console.log(mySkey.position)
mySkey.setDate(new Date('2018-04-05'))

扩展接口

和类一样,接口也可以相互扩展

interface FatherInterface {
  surname: string;    // 中国的姓氏
  shape: string;      // 外貌,孩子要是不像父亲。。。。。。
}
interface SonInterface extends FatherInterface {
  isClever: boolean;
}
let son: SonInterface = { surname: 'deng', shape: 'cool', isClever: true }

而且一个接口可以继承多个接口,就像一个孩子继承了父亲,母亲,爷爷,奶奶······

interface FatherInterface {
  surname: string;    // 中国的姓氏
  shape: string;      // 外貌,孩子要是不像父亲。。。。。。
}
interface MathorInterface {
  isCareful: boolean
}
interface SonInterface extends FatherInterface, MathorInterface {
  isClever: boolean;
}
let son: SonInterface = { surname: 'deng', shape: 'cool', isCareful: false, isClever: true }

接口继承类

接口同样会继承到类的private和protected成员

class Father {
  private surname: any;
  public shape: string = '';
}
interface SonInterface extends Father {

}
class Son extends Father{
  shape = 'cool'
}
let son = new Son();
console.log(son.shape)    // cool