MST

星途 面试题库

面试题:TypeScript 类型别名 type 与接口 interface 的深度比较

阐述 TypeScript 中类型别名 type 和接口 interface 的主要区别,在哪些场景下更适合使用 type,哪些场景下更适合使用 interface,并举例说明。
36.8万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

主要区别

  1. 定义方式
    • type:使用type关键字定义,例如type UserType = { name: string; age: number; };
    • interface:使用interface关键字定义,例如interface UserInterface { name: string; age: number; }
  2. 类型覆盖与合并
    • type:不支持合并,如果定义相同名称的type会报错。例如:
    type UserType = { name: string; };
    type UserType = { age: number; }; // 报错,重复定义
    
    • interface:支持同名接口合并,将属性合并在一起。例如:
    interface UserInterface { name: string; }
    interface UserInterface { age: number; }
    // 合并后UserInterface为 { name: string; age: number; }
    
  3. 类型别名可用于原始类型、联合类型和元组类型
    • type:可以为原始类型创建别名,如type StringAlias = string;,也能定义联合类型别名type StringOrNumber = string | number;,还能定义元组类型别名type MyTuple = [string, number];
    • interface:不能用于原始类型、联合类型和元组类型定义。
  4. 实现与扩展
    • type:通过交叉类型&实现类似接口扩展功能,例如type AdminType = UserType & { role: string; };
    • interface:使用extends关键字扩展,例如interface AdminInterface extends UserInterface { role: string; }

适用场景

  1. 适合使用 type 的场景
    • 联合类型和交叉类型:当需要定义联合类型或交叉类型时,type更合适。例如,一个函数可以接收字符串或数字类型参数:
    type StringOrNumber = string | number;
    function printValue(value: StringOrNumber) {
        console.log(value);
    }
    
    • 原始类型别名:为原始类型创建更具描述性的别名,如在处理特定字符串类型时。
    type Email = string;
    function sendEmail(to: Email, message: string) {
        console.log(`Sending email to ${to}: ${message}`);
    }
    
  2. 适合使用 interface 的场景
    • 对象类型定义且可能需要合并:如果定义对象类型,并且后续可能会有其他部分添加相同接口的属性,interface的合并特性很有用。例如,在模块化开发中不同模块对用户信息的扩展。
    interface User {
        name: string;
    }
    interface User {
        age: number;
    }
    let user: User = { name: 'John', age: 30 };
    
    • 实现接口(implements):当一个类需要实现某个类型定义时,interface更符合习惯。例如:
    interface Shape {
        area(): number;
    }
    class Circle implements Shape {
        constructor(public radius: number) {}
        area(): number {
            return Math.PI * this.radius * this.radius;
        }
    }