Skip to content

Interface接口

接口 · TypeScript中文网 · TypeScript——JavaScript的超集

TS中,接口用于定义和约束对象的结构,定义对象的形状(Shape)

类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。

typescript
// 定义一个接口
interface Person {
  firstName: string;
  lastName: string;
  age: number;
}

// 使用接口来约束对象的形状
let person: Person = {
  firstName: "John",
  lastName: "Doe",
  age: 30
};
  • 每一个属性的值必须一一对应到接口的属性类型
  • 不能有多的属性,也不能有少的属性,包括直接在对象内部声明,或是 obj1.other = 'xxx' 这样属性访问赋值的形式

可选属性

typescript
// 注意,接口分号结尾
interface Car {
  make: string;
  model: string;
  year?: number; // 可选属性
}

let myCar: Car = {
  make: "Toyota",
  model: "Camry"
};

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值。 readonly是作为对象的属性使用!!! readonly => 防止对象的属性被再次赋值

typescript
interface Point {
  readonly x: number;
  readonly y: number;
}

//  赋值后,x和y再也不能被改变了。
const point: Point = { x: 10, y: 20 };
point.x = 30; // Error: 
// Cannot assign to 'x' because it is a read-only property.

额外属性检查

typescript
interface Person {
  name: string;
  age: number;
}

let john: Person = {
  name: "John",
  age: 30,
  // 错误: 对象文字可以只指定已知属性,并且 'gender' 不在类型 'Person' 中。
  gender: "male"
};

TypeScript 报告了一个错误,因为 gender 属性不在 Person 接口中定义。为了解决这个问题,有几种方法:

使用类型断言

typescript
let john: Person = {
  name: "John",
  age: 30,
  gender: "male" // 使用类型断言,告诉编译器你知道这是安全的
} as Person;

添加字符串索引签名

typescript
interface Person {
  name: string;
  age: number;
  [key: string]: any; // 添加索引签名,允许包含额外的属性
}

let john: Person = {
  name: "John",
  age: 30,
  gender: "male"
};
// 它允许将任意类型的属性添加到对象中。
// 使用类型断言或类型别名可能更灵活,具体取决于你的需求和设计决策。

函数类型的接口

在 TypeScript 中,可以使用函数类型的接口来定义函数的形状,以明确函数参数和返回值的类型

参数列表里的每个参数都需要名字和类型。

typescript
// 定义一个函数类型的接口
interface MathOperation {
  (x: number, y: number): number;
}

// 使用函数类型接口来定义一个加法函数
let add: MathOperation = function(x, y) {
  return x + y;
}
// 使用函数类型接口来定义一个乘法函数
let multiply: MathOperation = function(x, y) {
  return x * y;
}

类类型的接口-实现类-implements

可以使用接口(interface)来描述类的类型。通过接口,可以定义类应该具有哪些属性和方法。

typescript
// 定义一个接口
interface Animal {
  name: string;
  makeSound(): void;
}

// 实现接口的类
class Dog implements Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound(): void {
    console.log("Woof! Woof!");
  }
}

// 实例化类
const myDog: Animal = new Dog("Buddy");

// 调用方法
myDog.makeSound();

Animal 是一个接口,它规定了类应该具有 name 属性和 makeSound 方法。然后,Dog 类实现了这个接口,确保它有这两个属性和方法。。

继承接口-extends

接口继承允许你创建一个新接口,该接口包含已有接口的所有成员,同时可以添加新的成员或覆盖现有成员。

typescript
// 基础接口
interface Shape {
  color: string;
}

// 继承基础接口并添加新的属性
interface Square extends Shape {
  sideLength: number;
}

// 使用继承后的接口
const square: Square = {
  color: "red",
  sideLength: 10,
};

继承多个接口,逗号隔开

一个接口可以继承多个接口,创建出多个接口的合成接口。

typescript
interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

// Square继承了Shape,PenStroke两个接口
interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

type 与 interface

很多同学更喜欢用 type(Type Alias,类型别名)来代替接口结构描述对象,更推荐的方式是,interface 用来描述对象、类的结构,而类型别名用来将一个函数签名、一组联合类型、一个工具类型等等抽离成一个完整独立的类型。但大部分场景下接口结构都可以被类型别名所取代,因此,只要你觉得统一使用类型别名让你觉得更整齐,也没什么问题。