返回文章列表

文章

TypeScript中interface的用法

TypeScript 中的 interface (接口) 是一种强大的特性,用于定义对象的“形状”或“契约”。

目录
  1. interface** 的核心概念**
  2. interface** 的基本用法**
  3. 1. 定义对象类型
  4. 2. 定义函数类型
  5. 3. 定义可索引类型
  6. 4. 定义类实现接口
  7. 5. 扩展接口 (Extending Interfaces)
  8. 6. 混合类型 (Hybrid Types)
  9. interface** 与 type 的区别**
  10. 总结

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 代码的关键。