Laucher
2022年 10月 11日
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
的接口,它包含name
和age
两个属性,类型分别为string
和number
。然后我们创建了两个满足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;
}