知识篇 -- TypeScript接口:定义对象的形状

Ray Shine 2024/5/20 TypeScript基础知识接口

在TypeScript中,接口(Interfaces) 是一个非常强大的概念,它用于定义对象的“形状”(Shape)。接口可以对类、函数以及普通对象进行结构上的约束,确保它们符合预期的类型定义。通过使用接口,我们可以在编译阶段捕获类型错误,从而提高代码的健壮性、可读性和可维护性。

# 什么是TypeScript接口?

接口是TypeScript中定义自定义类型的一种方式,它描述了一个对象应该拥有的属性和方法。接口只关注对象的结构,而不关心对象的具体实现。这使得接口成为实现“鸭子类型”(Duck Typing)的关键工具——“如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子”。

接口的主要作用

  • 类型检查:在编译时对对象的结构进行检查,确保其符合接口定义。
  • 代码约定:为代码提供清晰的约定,方便团队协作和代码维护。
  • 抽象:定义抽象的类型,而不涉及具体的实现细节。

# 1. 对象类型接口

最常见的接口用法是定义普通JavaScript对象的形状。

示例

interface Person {
    firstName: string;
    lastName: string;
    age: number;
}

function greet(person: Person) {
    console.log(`Hello, ${person.firstName} ${person.lastName}! You are ${person.age} years old.`);
}

let user = { firstName: 'Jane', lastName: 'Doe', age: 30 };
greet(user); // OK

// greet({ firstName: 'John', age: 25 }); // Error: Property 'lastName' is missing in type '{ firstName: string; age: number; }'

# 可选属性

接口中的属性可以标记为可选属性,使用 ? 符号。这意味着该属性可以存在,也可以不存在。

示例

interface Config {
    width?: number;
    height?: number;
    color: string;
}

function createConfig(config: Config): { color: string; width: number; height: number } {
    let newConfig = { color: 'white', width: 100, height: 100 };
    if (config.width) {
        newConfig.width = config.width;
    }
    if (config.height) {
        newConfig.height = config.height;
    }
    newConfig.color = config.color; // color是必选属性
    return newConfig;
}

let myConfig = createConfig({ color: 'black', width: 200 }); // OK
// let invalidConfig = createConfig({ width: 100 }); // Error: Property 'color' is missing

# 只读属性

接口中的属性可以标记为只读属性,使用 readonly 关键字。一旦赋值,就不能再修改。

示例

interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
// p1.x = 5; // Error: Cannot assign to 'x' because it is a read-only property.

TypeScript还提供了 ReadonlyArray<T> 类型,确保数组创建之后不能被修改。

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
// ro[0] = 12; // Error
// ro.push(5); // Error
// ro.length = 100; // Error
// a = ro; // Error: ReadonlyArray不能赋值给普通Array
a = ro as number[]; // 可以通过类型断言覆盖

# 2. 函数类型接口

接口不仅可以描述对象的属性,还可以描述函数的类型。

示例

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
    let result = src.search(sub);
    return result > -1;
};

// mySearch = function(src: string, sub: number): boolean { // Error: Type 'number' is not assignable to type 'string'.
//     let result = src.search(sub.toString());
//     return result > -1;
// };

# 3. 可索引接口

可索引接口用于描述那些可以通过索引访问的类型,例如数组或字典(对象)。

示例

interface StringArray {
    [index: number]: string; // 数字索引,返回字符串
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0]; // "Bob"

interface Dictionary {
    [key: string]: string; // 字符串索引,返回字符串
}

let myDict: Dictionary = { "name": "Alice", "city": "New York" };
let cityName: string = myDict["city"]; // "New York"

// 注意:数字索引的返回值必须是字符串索引返回值的子类型
interface MixedArray {
    [index: number]: string;
    length: number; // OK
    // name: number; // Error: 数字索引的返回值类型是string,而name属性的返回值类型是number,不兼容
}

# 4. 类类型接口

接口可以对类的一部分行为进行抽象。它描述了类的公共部分,而不是私有部分。

示例

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date): void;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

注意:类类型接口只检查类的实例部分,不检查类的静态部分。如果需要检查静态部分,需要单独定义。

# 5. 接口的继承

接口可以像类一样相互继承,从而扩展已有的接口。

示例

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square: Square = { color: "blue", sideLength: 10 };

interface PenStroke {
    penWidth: number;
}

interface Drawing extends Shape, PenStroke {
    // Drawing 继承了 color 和 penWidth
    // 并且可以有自己的属性
    scale: number;
}

let drawing: Drawing = { color: "red", penWidth: 2, scale: 0.5 };

# 总结

TypeScript接口是定义对象形状、函数类型、可索引类型和类行为的强大工具。通过合理使用接口,开发者可以为代码提供清晰的类型约定,在编译阶段捕获潜在错误,从而显著提高代码的质量、可读性和可维护性。掌握接口是深入理解TypeScript和构建大型、复杂前端应用的关键一步。

最后更新时间: 2025/11/20 22:59:30
ON THIS PAGE