本文共 3181 字,大约阅读时间需要 10 分钟。
TypeScript 的核心原则之一是通过对值的结构进行类型检查,它被称为“鸭式辨型法”或“结构性子类型化”。接口在 TypeScript 中起到了重要作用,为代码或第三方代码定义契约。
接口就像一个命名的类型,它描述了一个对象的外形。例如,假设你有一个函数,它期望传入一个具有 label
属性且类型为 string
的对象,你可以使用接口来定义这个期望的外形。
interface LabelledValue { label: string;}function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label);}let myObj = { size: 10, label: "Size 10 Object"};printLabel(myObj);
需要注意的是,TypeScript 不会检查传入对象中是否有其他属性或属性顺序,只要满足基本需求的属性和类型即可。
接口中的属性并不一定是必需的,有些可能只有在特定条件下存在。可选属性在“选项包模式”中非常常用,即函数传入的参数对象中可能没有所有属性都赋值。
interface SquareConfig { color?: string; width?: number;}function createSquare(config: SquareConfig): { color: string; area: number} { let newSquare = { color: "white", area: 100 }; if (config.color) { newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare;}let mySquare = createSquare({ color: "black" });
使用 ?
符号可以在属性名后面表示可选属性。可选属性的好处在于可以预定义可能存在的属性,并能检查引用了不存在的属性时的错误。
有些属性只能在对象创建时修改,TypeScript 提供了 readonly
关键字来定义只读属性。
interface Point { readonly x: number; readonly y: number;}let p1: Point = { x: 10, y: 20 };// p1.x = 5; // 给定错误
同时,ReadonlyArray<T>
类型可以确保数组创建后无法修改它的内容。
let a: number[] = [1, 2, 3, 4];let ro: ReadonlyArray= a;ro[0] = 12; // 错误ro.push(5); // 错误ro.length = 100; // 错误a = ro; // 错误
如果想将 ReadonlyArray
赋值给普通数组,可以使用类型断言。
a = ro as number[];
接口也可以描述函数的类型,通过在接口中定义调用签名。
interface SearchFunc { (source: string, subString: string): boolean;}let mySearch: SearchFunc;mySearch = function (source: string, subString: string) { // ...};
函数参数和返回值的类型都会被检查,TypeScript 会自动推断这些类型。
可索引类型允许通过数组或对象的索引访问特定的属性。
interface StringArray { [index: number]: string;}let myArray: StringArray = ["Bob", "Fred"];let myStr: string = myArray[0];
索引签名可以是数字或字符串。数字签名要求索引后的返回值是字符串。同时,可以使用只读索引签名来防止赋值。
interface ReadonlyStringArray { readonly [index: number]: string;}let myArray: ReadonlyStringArray = ["Alice", "Bob"];myArray[2] = "Mallory"; // 错误
类和接口之间的关系与其它语言有所不同,接口描述的是一个类的实例部分,而不会继承类的静态部分。
interface ClockInterface { currentTime: Date; setTime(d: Date);}class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { // ... } constructor(h: number, m: number) { // ... }}
接口继承可以继承多个接口,形成复合接口。
类似于类,接口也可以继承其他接口,这让您可以将接口分割到模块中。
interface Shape { color: string;}interface Square extends Shape { sideLength: number;}let square: Square = { color: "blue", sideLength: 10 };
有时,您需要一个对象同时具有多种类型,例如函数和属性。
interface Counter { (start: number): string; interval: number; reset(): void;}function getCounter(): Counter { // ...}let c = getCounter();c(10); // 调用函数c.interval = 5; // 修改属性c.reset(); // 调用方法
当接口继承一个类类型时,接口会继承类的实例部分,包括私有和受保护成员。
class Control { private state: any;}interface SelectableControl extends Control { select(): void;}class Button extends Control implements SelectableControl { select() { // ... }}class Image implements SelectableControl { select() { // ... }}// 错误:Image 不具有 Control 的私有成员 state
通过以上示例可以看出,接口能够非常灵活地描述 JavaScript 中各种复杂的对象结构。
转载地址:http://jrjaz.baihongyu.com/