文章目录
- 一、TypeScript 接口
- 1. 属性接口
- 2. 方法接口
- 3. 可选属性和只读属性
- 4. 索引签名
- 二、TypeScript 接口继承
- 1. 单继承
- 2. 多继承的替代方案
- 三、TypeScript 接口与数组
- 四、TypeScript 接口与联合类型
- 五、相关链接
一、TypeScript 接口
在 TypeScript 中,接口(Interfaces)是一个非常重要的概念,它用于定义对象的形状,即对象应该有哪些属性和方法。但接口本身并不实现任何功能,它只是定义了契约,其他类型(如类、对象字面量等)必须遵循这个契约。
以下是 TypeScript 接口的一些基本用法:
1. 属性接口
定义一个只包含属性的接口:
interface Person {name: string;age: number;
}let person: Person = {name: 'Alice',age: 25
};
在这个例子中,Person
接口定义了一个对象应该具有 name
(类型为 string
)和 age
(类型为 number
)两个属性。然后,我们创建了一个 Person
类型的变量 person
,并给它分配了一个满足这个接口定义的对象。
2. 方法接口
接口也可以定义方法:
interface Greeter {greet(name: string): void;
}class PersonGreeter implements Greeter {greet(name: string) {return 'Hello, ' + name;}
}let greeter: Greeter = new PersonGreeter();
console.log(greeter.greet('Alice')); // 输出 "Hello, Alice"
在这个例子中,Greeter
接口定义了一个方法 greet
,该方法接受一个 string
类型的参数,并返回 void
(即不返回任何值)。然后,我们创建了一个 PersonGreeter
类,该类实现了 Greeter
接口,并提供了 greet
方法的实现。
3. 可选属性和只读属性
接口中的属性可以是可选的,也可以是只读的:
interface OptionalPerson {name: string;age?: number; // 可选属性readonly id: number; // 只读属性
}let optionalPerson: OptionalPerson = {name: 'Bob',id: 123
};// optionalPerson.age = 26; // 错误,因为 age 是可选的,但并未在此处赋值
// optionalPerson.id = 456; // 错误,因为 id 是只读的
在这个例子中,OptionalPerson
接口定义了一个可选的 age
属性和一个只读的 id
属性。注意,只读属性在第一次赋值后就不能再被修改。
4. 索引签名
接口也可以定义索引签名,用于描述对象可以有哪些索引以及这些索引的类型:
interface StringDictionary {[key: string]: string;
}let dict: StringDictionary = {firstName: 'Alice',lastName: 'Smith'
};// dict.someNumber = 123; // 错误,因为索引签名只允许 string 类型的键和 string 类型的值
在这个例子中,StringDictionary
接口定义了一个索引签名,表示该对象可以有任意数量的字符串类型的键和对应的字符串类型的值。
二、TypeScript 接口继承
在 TypeScript 中,接口(Interfaces)是支持单继承的,即一个接口可以继承自另一个接口。但是,TypeScript 不支持接口的多继承,即一个接口不能直接继承自多个接口。这是因为多重继承在面向对象编程中往往会导致复杂的继承层次和潜在的“菱形问题”(diamond problem)。
1. 单继承
在 TypeScript 中,你可以使用 extends
关键字来定义接口的继承关系。以下是一个单继承的示例:
interface Animal {name: string;eat(): void;
}interface Dog extends Animal {bark(): void;
}let myDog: Dog = {name: 'Buddy',eat() {console.log('Dog is eating');},bark() {console.log('Woof woof!');}
};
在这个例子中,Dog
接口继承了 Animal
接口,并添加了 bark
方法。任何实现 Dog
接口的对象都必须实现 name
、eat
和 bark
这三个属性和方法。
2. 多继承的替代方案
虽然 TypeScript 不支持接口的多继承,但你可以使用交叉类型(Intersection Types)来实现类似的效果。交叉类型是将多个类型合并为一个类型,你可以将它看作是多重继承的“模拟”。
以下是一个使用交叉类型实现类似多继承的示例:
interface Bird {fly(): void;layEggs(): void;
}interface Mammal {giveBirth(): void;eat(): void;
}// 使用交叉类型合并 Bird 和 Mammal
type Bat = Bird & Mammal;let myBat: Bat = {fly() {console.log('Flying');},layEggs() {console.log('Laying eggs (even though bats don\'t really do this)');},giveBirth() {console.log('Giving birth to live young');},eat() {console.log('Eating insects');}
};
在这个例子中,我们定义了两个接口 Bird
和 Mammal
,然后使用交叉类型 Bat = Bird & Mammal
创建了一个新类型 Bat
,它同时包含了 Bird
和 Mammal
的方法。任何符合 Bat
类型的对象都必须实现 fly
、layEggs
、giveBirth
和 eat
这四个方法。
虽然交叉类型在语法上看起来类似于多重继承,但它们之间有一些重要的区别。交叉类型不会创建一个继承层次结构,而是简单地将多个类型合并为一个类型。因此,它们不会遇到多重继承可能导致的复杂性和问题。
三、TypeScript 接口与数组
接口可以定义包含数组的属性。这允许你指定数组中的元素类型以及数组自身的其他属性(尽管数组本身没有除 length
和方法之外的属性)。
interface User {name: string;age: number;
}interface UserList {users: User[]; // 定义一个User类型的数组count: number; // 可能表示用户的数量
}const userList: UserList = {users: [{ name: 'Alice', age: 25 },{ name: 'Bob', age: 30 },],count: 2
};
在这个例子中,UserList
接口有一个 users
属性,它是一个 User
类型的数组。同时,UserList
还定义了一个 count
属性,可能用于存储用户的数量。
四、TypeScript 接口与联合类型
联合类型(Union Types)允许一个变量是几种类型之一。然而,接口本身并不直接与联合类型关联,但你可以使用接口与联合类型结合来定义复杂的类型。
联合类型通常使用 |
符号来定义,表示一个值可以是几种类型中的任何一种。
interface Square {kind: "square";size: number;
}interface Rectangle {kind: "rectangle";width: number;height: number;
}// 使用联合类型来定义一个变量可以是 Square 或 Rectangle
let shape: Square | Rectangle;shape = { kind: "square", size: 100 };
// 或者
shape = { kind: "rectangle", width: 100, height: 50 };// 使用类型守卫来区分不同的类型
function getArea(shape: Square | Rectangle): number {if (shape.kind === "square") {return shape.size * shape.size;} else {return shape.width * shape.height;}
}
在这个例子中,我们定义了两个接口 Square
和 Rectangle
,它们分别描述了正方形和矩形的属性。然后,我们定义了一个变量 shape
,它可以是 Square
或 Rectangle
类型之一。我们还定义了一个 getArea
函数,它接受一个 Square | Rectangle
类型的参数,并使用类型守卫(Type Guards)来区分不同的类型,并返回相应的面积。
需要注意的是,尽管在这个例子中我们没有直接在接口中使用联合类型,但联合类型与接口的结合使得我们可以定义更加复杂和灵活的类型系统。
五、相关链接
- TypeScript中文网
- TypeScript下载
- TypeScript文档
- 「TypeScript系列」TypeScript 简介及基础语法
- 「TypeScript系列」TypeScript 基础类型
- 「TypeScript系列」TypeScript 变量声明
- 「TypeScript系列」TypeScript 运算符
- 「TypeScript系列」TypeScript 条件语句
- 「TypeScript系列」TypeScript 循环
- 「TypeScript系列」TypeScript 函数
- 「TypeScript系列」TypeScript Number
- 「TypeScript系列」TypeScript String
- 「TypeScript系列」TypeScript Array(数组)
- 「TypeScript系列」TypeScript Map 对象
- 「TypeScript系列」TypeScript 元组
- 「TypeScript系列」TypeScript 联合类型/联合类型数组