Typescript

77 阅读3分钟

面试题

Q1、TS 中 typeinterface 区别?

在TypeScript中,typeinterface 都用于定义数据类型,但它们有一些重要的区别和各自的使用场景。以下是它们的主要区别和各自特点:

type 类型

  1. 定义基本类型别名:

    type Name = string;
    type Age = number;
    
  2. 联合类型和交叉类型:

    type StringOrNumber = string | number;
    type Person = { name: string } & { age: number };
    
  3. 复杂类型定义:

    type User = {
      name: string;
      age: number;
      isActive: boolean;
    };
    
  4. 映射类型:

    type ReadonlyUser = Readonly<User>;
    
  5. 元组:

    type Point = [number, number];
    

interface 接口

  1. 对象类型定义:

    interface User {
      name: string;
      age: number;
      isActive: boolean;
    }
    
  2. 可扩展性: 接口可以被扩展(继承),使得复用和扩展更方便。

    interface Employee extends User {
      salary: number;
    }
    
  3. 合并声明: 同一个接口名的多个声明会自动合并。

    interface User {
      address: string;
    }
    // 上面的 User 接口会合并为:
    interface User {
      name: string;
      age: number;
      isActive: boolean;
      address: string;
    }
    

主要区别

  1. 扩展性

    • interface 可以通过 extends 来扩展。
    • type 可以通过交叉类型(&)来组合,但不能直接扩展。
  2. 合并声明

    • interface 会自动合并同名接口的声明。
    • type 不会自动合并同名类型的声明。
  3. 使用场景

    • 如果需要定义一个对象类型并且可能需要扩展或多次声明时,使用 interface
    • 如果需要定义联合类型、交叉类型、或者更复杂的类型别名,使用 type

示例比较

使用 type 定义联合类型和交叉类型

type StringOrNumber = string | number;
type NameAndAge = { name: string } & { age: number };

使用 interface 定义可扩展对象类型

interface User {
  name: string;
  age: number;
}
interface Employee extends User {
  salary: number;
}

Q2:对象的属性不确定时,如何定义接口(interface)?

如下图,直接写空对象肯定是不行的。

企业微信截图_17231706021009.png

1. 使用索引签名

如果 data 对象中的属性是动态的且不固定,可以使用索引签名来定义:

export interface ISideslider {
  isShow: boolean;
  title: string;
  data: { [key: string]: any };
}

2. 使用泛型

使用泛型可以让 ISideslider 接口在实例化时指定 data 的具体类型:

export interface ISideslider<T = any> {
  isShow: boolean;
  title: string;
  data: T;
}

然后在使用时可以传入具体的类型:

interface IData {
  id: number;
  name: string;
  // 其他属性
}

const sideslider: ISideslider<IData> = {
  isShow: true,
  title: "Example Title",
  data: {
    id: 1,
    name: "Example Name",
    // 其他属性
  }
};

3. 使用 Record 类型

如果 data 对象的键和值都是字符串,可以使用 Record<string, any>

export interface ISideslider {
  isShow: boolean;
  title: string;
  data: Record<string, any>;
}

Q3:讲讲 Partial

Partial 是 TypeScript 中的一个内置工具类型,用来将对象类型的所有属性变为可选属性。使用 Partial 后,原本要求必须存在的属性变成了可以存在,也可以不定义。它适用于某些情况下,你只需要对象的部分属性,而不是全部。

基本用法

type User = {
    name: string;
    age: number;
    email: string;
};

const partialUser: Partial<User> = {
    name: 'Alice'
};

解释

  • Partial<User>User 类型中的所有属性 (name, age, email) 都变成了可选的。
  • 这样,你可以只定义一部分属性(例如 name),而不必定义所有属性。

实现机制

Partial 是通过 TypeScript 的泛型和映射类型实现的,定义如下:

type Partial<T> = {
    [P in keyof T]?: T[P];
};
  • T 是传入的类型。
  • keyof T 获取类型 T 中的所有属性名称。
  • P in keyof T 通过遍历这些属性名称,生成一个新的类型。
  • ? 将这些属性标记为可选属性。

使用场景

  1. 函数参数:在不需要传递所有属性的情况下,可以使用 Partial 让某些参数变为可选。

    function updateUser(user: Partial<User>) {
        // 可以只更新部分属性
    }
    
  2. 状态管理:在某些应用场景(如 React 状态管理)中,通常只需要更新部分状态值,用 Partial 可以简化状态更新。

    const newState: Partial<AppState> = {
        isLoading: true
    };