接口定义和使用

1. 接口简介

在 TypeScript 中,接口(Interface)是一种定义对象结构的方式。它用于描述对象的形状,即对象应该具有哪些属性和方法。接口可以帮助我们在编写代码时确保对象的一致性,从而提高代码的可维护性和可读性。

1.1 为什么使用接口?

接口的主要作用是:

  • 类型检查:确保对象具有预期的属性和方法。
  • 代码复用:通过接口定义通用的对象结构,减少重复代码。
  • 提高代码可读性:接口清晰地描述了对象的结构,使代码更易于理解。

2. 接口的基本定义

在 TypeScript 中,接口使用 interface 关键字来定义。接口可以包含属性、方法和索引签名等。

2.1 定义一个简单的接口

interface Person {
    name: string;
    age: number;
}

在这个例子中,我们定义了一个名为 Person 的接口,它有两个属性:name 和 age。name 是一个字符串类型,age 是一个数字类型。

2.2 使用接口

定义好接口后,我们可以使用它来声明对象。

let person: Person = {
    name: "Alice",
    age: 30
};

在这个例子中,我们声明了一个 person 对象,并将其类型指定为 Person。TypeScript 会检查 person 对象是否符合 Person 接口的定义。

3. 可选属性和只读属性

3.1 可选属性

有时候,对象的某些属性可能不是必需的。我们可以使用 ? 符号来定义可选属性。

interface Person {
    name: string;
    age?: number; // age 是可选属性
}

let person: Person = {
    name: "Alice"
};

在这个例子中,age 属性是可选的,因此 person 对象可以不包含 age 属性。

3.2 只读属性

如果我们希望某些属性在对象创建后不能被修改,可以使用 readonly 关键字。

interface Person {
    readonly id: number;
    name: string;
    age?: number;
}

let person: Person = {
    id: 1,
    name: "Alice"
};

// person.id = 2; // 错误:id 是只读属性

在这个例子中,id 属性是只读的,一旦赋值后就不能再修改。

4. 函数类型接口

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

4.1 定义函数类型接口

interface GreetFunction {
    (name: string): string;
}

在这个例子中,我们定义了一个名为 GreetFunction 的接口,它描述了一个函数类型。这个函数接受一个 string 类型的参数 name,并返回一个 string 类型的值。

4.2 使用函数类型接口

let greet: GreetFunction = function(name: string) {
    return `Hello, ${name}!`;
};

console.log(greet("Alice")); // 输出: Hello, Alice!

在这个例子中,我们声明了一个 greet 函数,并将其类型指定为 GreetFunction。TypeScript 会检查 greet 函数的参数和返回值是否符合 GreetFunction 接口的定义。

5. 类类型接口

接口还可以用于描述类的结构。通过实现接口,类可以确保自己具有接口中定义的属性和方法。

5.1 定义类类型接口

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

在这个例子中,我们定义了一个名为 ClockInterface 的接口,它包含一个 currentTime 属性和一个 setTime 方法。

5.2 实现类类型接口

class Clock implements ClockInterface {
    currentTime: Date;

    constructor(h: number, m: number) {
        this.currentTime = new Date();
    }

    setTime(d: Date) {
        this.currentTime = d;
    }
}

在这个例子中,我们定义了一个 Clock 类,并使用 implements 关键字来实现 ClockInterface 接口。Clock 类必须包含 currentTime 属性和 setTime 方法,否则 TypeScript 会报错。

6. 继承接口

接口可以继承其他接口,从而扩展接口的功能。

6.1 定义继承接口

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

在这个例子中,我们定义了一个 Shape 接口和一个 Square 接口。Square 接口继承了 Shape 接口,因此 Square 接口包含了 color 属性和 sideLength 属性。

6.2 使用继承接口

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

在这个例子中,我们声明了一个 square 对象,并将其类型指定为 Square。TypeScript 会检查 square 对象是否符合 Square 接口的定义,包括继承自 Shape 接口的 color 属性。

7. 类型别名 vs 接口

在 TypeScript 中,类型别名(Type Alias)和接口都可以用来定义类型。它们有一些相似之处,但也有一些区别。

7.1 类型别名

类型别名使用 type 关键字来定义。它可以用来定义任何类型,包括基本类型、联合类型、交叉类型等。

type Point = {
    x: number;
    y: number;
};

7.2 接口

接口使用 interface 关键字来定义。它主要用于定义对象的形状。

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

7.3 选择使用类型别名还是接口

  • 对象形状:如果需要定义对象的形状,通常使用接口。
  • 复杂类型:如果需要定义复杂的类型,如联合类型、交叉类型等,通常使用类型别名。

8. 实践练习

8.1 练习1:定义一个接口

定义一个名为 Car 的接口,包含以下属性:

  • make:字符串类型
  • model:字符串类型
  • year:数字类型
  • isElectric:布尔类型

然后创建一个符合该接口的对象。

interface Car {
    make: string;
    model: string;
    year: number;
    isElectric: boolean;
}

let myCar: Car = {
    make: "Tesla",
    model: "Model S",
    year: 2022,
    isElectric: true
};

8.2 练习2:使用函数类型接口

定义一个名为 Calculator 的接口,包含一个名为 add 的函数,该函数接受两个数字参数并返回它们的和。然后实现该接口。

interface Calculator {
    add(a: number, b: number): number;
}

let calculator: Calculator = {
    add: function(a: number, b: number) {
        return a + b;
    }
};

console.log(calculator.add(5, 3)); // 输出: 8

8.3 练习3:继承接口

定义一个名为 Animal 的接口,包含一个 name 属性和一个 makeSound 方法。然后定义一个名为 Dog 的接口,继承 Animal 接口,并添加一个 breed 属性。最后创建一个符合 Dog 接口的对象。

interface Animal {
    name: string;
    makeSound(): void;
}

interface Dog extends Animal {
    breed: string;
}

let myDog: Dog = {
    name: "Buddy",
    breed: "Golden Retriever",
    makeSound: function() {
        console.log("Woof!");
    }
};

myDog.makeSound(); // 输出: Woof!

9. 总结

接口是 TypeScript 中非常重要的概念,它帮助我们定义对象的结构,确保代码的一致性和可维护性。通过本教程,你应该已经掌握了如何定义和使用接口,包括可选属性、只读属性、函数类型接口、类类型接口以及接口的继承。希望这些知识能够帮助你在实际项目中更好地使用 TypeScript。