logo
Laucher

Laucher

Laucher

2022年 10月 11日

0

TypeScript的接口和对象类型

接口是TypeScript中非常灵活和可重用的概念,它可以用于定义对象的结构、函数类型、类的结构等。使用接口可以使代码更具可读性和可维护性,并提高代码的复用性。

封面图

什么是接口和对象类型?

在学习TypeScript时,接口和对象类型是非常重要的概念。它们允许我们定义自定义的数据类型,使代码更加清晰、可读和可维护。接口用于描述对象的结构,包括属性和方法的类型,而对象类型是指具体的对象实例,它符合相应接口的定义。

接口的基本使用

接口可以用于定义对象的结构,类似于合同,对象必须满足接口定义的要求。接口使用interface关键字来声明。

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

// 以下对象满足Person接口的要求
let person1: Person = {
  name: "Alice",
  age: 30,
};

let person2: Person = {
  name: "Bob",
  age: 25,
};

在上面的例子中,我们定义了一个名为Person的接口,它包含nameage两个属性,类型分别为stringnumber。然后我们创建了两个满足Person接口要求的对象。

可选属性

有时候对象的属性并非必须的,我们可以使用可选属性来描述这种情况。在属性名称后面加上?符号,表示该属性是可选的。

interface Person {
  name: string;
  age: number;
  email?: string; // email属性是可选的
}

let person1: Person = {
  name: "Alice",
  age: 30,
};

let person2: Person = {
  name: "Bob",
  age: 25,
  email: "bob@example.com",
};

在上面的例子中,我们给Person接口添加了一个可选属性email,这样在创建对象时,可以选择是否包含email属性。

只读属性

有时候我们希望对象的某些属性在创建后不能被修改,可以使用readonly关键字来定义只读属性。

interface Person {
  readonly id: number;
  name: string;
  age: number;
}

let person: Person = {
  id: 1,
  name: "Alice",
  age: 30,
};

// Error: 无法分配到 "id" ,因为它是只读属性
person.id = 2;

在上面的例子中,我们给Person接口的id属性添加了readonly修饰符,这样一旦对象被创建,id属性就不能再被修改。

函数类型

接口不仅可以描述对象的结构,还可以描述对象的方法。

interface Calculator {
  (x: number, y: number): number;
}

let add: Calculator = function (x, y) {
  return x + y;
};

let subtract: Calculator = function (x, y) {
  return x - y;
};

在上面的例子中,我们定义了一个名为Calculator的接口,它描述了一个函数类型,该函数接受两个参数,并返回一个数字类型的结果。然后我们创建了两个满足Calculator接口要求的函数。

继承接口

接口之间也可以相互继承,这样一个接口可以继承另一个接口的成员。

interface Animal {
  type: string;
}

interface Dog extends Animal {
  breed: string;
}

let myDog: Dog = {
  type: "mammal",
  breed: "Golden Retriever",
};

在上面的例子中,我们定义了一个名为Animal的接口,它包含type属性。然后我们定义了一个名为Dog的接口,它通过extends关键字继承了Animal接口,同时添加了breed属性。这样,Dog接口就包含了Animal接口和自己的属性要求。

实现接口

在TypeScript中,我们不仅可以定义接口,还可以使用接口来约束类的结构。这种约束称为”实现接口”。

interface Shape {
  getArea(): number;
}

class Circle implements Shape {
  radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  getArea() {
    return Math.PI * this.radius * this.radius;
  }
}

任意属性

在接口中使用任意属性时,我们使用方括号[ ]来表示该属性是一个任意属性,并在方括号内指定属性名称的类型。

interface Person {
  name: string;
  age: number;
  [propertyName: string]: any;
}

let person1: Person = {
  name: "Alice",
  age: 30,
  gender: "female", // 任意属性
  occupation: "engineer", // 任意属性
};

在上面的例子中,我们定义了一个名为Person的接口,它包含name和age两个属性,类型分别为string和number。然后我们使用任意属性来表示Person接口可以接受除name和age之外的任意属性,并且这些属性的值可以是任意类型。

这样,我们就可以创建满足Person接口的对象,不仅包含name和age属性,还可以包含任意其他属性。

任意属性的注意事项

在使用任意属性时,需要注意以下几点:

  • 任意属性的类型必须是已知属性类型的子类型,这是为了确保类型安全。
  • 如果对象中包含了任意属性,那么它的属性数量可以比接口定义的属性数量多,但至少要包含接口定义的属性。
interface Person {
  name: string;
  age: number;
  [propertyName: string]: string; // 任意属性的类型为string
}

let person1: Person = {
  name: "Alice",
  age: 30,
  gender: "female", // 任意属性是合法的,类型为string
  // Error: 不能将类型“number”分配给类型“string”
  occupation: 123, // 任意属性必须是string类型
};
  • 任意属性的定义必须放在接口的最后面,否则会报错。
// Error: 任意属性的定义必须放在接口的最后
interface Person {
  [propertyName: string]: string;
  name: string;
  age: number;
}

评论