文章
TypeScript中interface的用法
TypeScript 中的 interface (接口) 是一种强大的特性,用于定义对象的“形状”或“契约”。
目录
TypeScript 中的 interface (接口) 是一种强大的特性,用于定义对象的“形状”或“契约”。它允许你指定对象应该具有哪些属性和方法,以及它们的类型,而不需要提供这些属性和方法的具体实现。这在编译时提供类型检查,帮助你在开发阶段捕获错误,提高代码的可维护性和健壮性。
interface** 的核心概念**#
- 定义对象的形状:
interface最主要的用途是描述一个对象应该包含哪些属性,以及这些属性的类型。 - 只定义不实现:
interface只声明成员的签名(名称和类型),不包含任何实现逻辑。 - 类型检查: TypeScript 编译器会根据
interface定义的契约来检查代码,确保对象符合预期的结构。 - “鸭子类型” (Duck Typing) 或结构化子类型 (Structural Subtyping): TypeScript 的类型检查是基于结构而不是基于名称的。如果一个对象的结构符合某个接口的定义,那么它就被认为是该接口的类型,即使它没有明确声明实现该接口。
interface** 的基本用法**#
1. 定义对象类型#
这是 interface 最常见的用法。
interface Person {
name: string;
age: number;
email?: string; // 可选属性,使用 ?
readonly id: number; // 只读属性,使用 readonly
}
const user: Person = {
id: 123,
name: "Alice",
age: 30,
};
// user.id = 456; // 错误:id 是只读属性
// user.gender = "female"; // 错误:Person 接口没有 gender 属性
const anotherUser: Person = {
id: 456,
name: "Bob",
age: 25,
email: "bob@example.com",
};
name: string;: 定义一个名为name的属性,类型为string。age?: number;: 定义一个可选属性age,类型为number。这意味着age属性可以存在也可以不存在。readonly id: number;: 定义一个只读属性id,类型为number。一旦初始化后,其值不能被修改。
2. 定义函数类型#
interface 也可以用来定义函数类型,指定函数的参数类型和返回值类型。
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (source: string, subString: string): boolean {
const result = source.indexOf(subString);
return result > -1;
};
console.log(mySearch("hello world", "world")); // true
3. 定义可索引类型#
可索引类型描述了当通过索引访问类型时,哪些类型是允许的。常见的有数字索引和字符串索引。
interface StringArray {
[index: number]: string; // 数字索引,键为 number,值为 string
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
console.log(myArray[0]); // "Bob"
interface Dictionary {
[key: string]: string; // 字符串索引,键为 string,值为 string
}
let myDict: Dictionary = {
name: "Alice",
city: "New York",
};
console.log(myDict["name"]); // "Alice"
4. 定义类实现接口#
类可以使用 implements 关键字来实现一个接口。这意味着类必须实现接口中定义的所有属性和方法。
interface Greeter {
greeting: string;
greet(): void;
}
class EnglishGreeter implements Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(): void {
console.log(`Hello, ${this.greeting}`);
}
}
const englishGreeter = new EnglishGreeter("World");
englishGreeter.greet(); // Hello, World
- 注意: 接口只检查类的实例部分,不检查类的静态部分。
5. 扩展接口 (Extending Interfaces)#
接口可以继承其他接口,从而组合多个接口的定义。
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square: Square = {
color: "blue",
sideLength: 10,
};
console.log(square.color); // blue
console.log(square.sideLength); // 10
一个接口也可以继承多个接口:
interface Pen {
write(): void;
}
interface Eraser {
erase(): void;
}
interface PenAndEraser extends Pen, Eraser {
length: number;
}
class Pencil implements PenAndEraser {
length: number;
constructor(len: number) {
this.length = len;
}
write(): void {
console.log("Writing with pencil...");
}
erase(): void {
console.log("Erasing with pencil...");
}
}
const pencil = new Pencil(15);
pencil.write();
pencil.erase();
6. 混合类型 (Hybrid Types)#
有时一个对象可能同时作为函数和对象使用,interface 也可以描述这种混合类型。
interface Counter {
(start: number): string; // 函数签名
interval: number; // 属性
reset(): void; // 方法
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) {
// ... function implementation
return "Counting from " + start;
};
counter.interval = 123;
counter.reset = function () {
// ... reset implementation
console.log("Counter reset");
};
return counter;
}
let c = getCounter();
console.log(c(10)); // Counting from 10
c.reset(); // Counter reset
console.log(c.interval); // 123
interface** 与 type 的区别**#
在 TypeScript 中,type (类型别名) 也可以定义类型,它们之间有很多相似之处,但也有一些重要的区别:
- 扩展性:
interface可以被extends扩展。type可以使用&(交叉类型) 来组合多个类型。interface可以被多次声明,并且 TypeScript 会自动合并它们的定义(声明合并)。type不支持声明合并。
- 用途:
interface主要用于定义对象的形状或类的契约。type可以定义原始类型、联合类型、元组、函数签名、以及对象的形状等更广泛的类型。
- 实现:
interface可以被类implements。type不能被类implements。 何时使用interface,何时使用type?
- 优先使用
interface来定义对象的形状。 它们更具可读性,并且支持声明合并,这在库和框架的类型定义中很有用。 - 当需要定义联合类型、元组类型或字面量类型时,使用
type。 - 当需要为现有类型创建别名时,使用
type。
总结#
interface 在 TypeScript 中是定义类型契约的重要工具,它提供:
- 强类型检查: 在编译时捕获类型相关的错误,提高代码质量。
- 代码可读性: 清晰地描述对象的结构,使代码更易于理解。
- 代码可维护性: 定义明确的契约,有助于团队协作和未来的代码修改。
- 代码复用: 通过扩展接口实现类型复用。
理解并熟练使用
interface是编写高质量 TypeScript 代码的关键。