面试题
Q1、TS 中 type 和 interface 区别?
在TypeScript中,type 和 interface 都用于定义数据类型,但它们有一些重要的区别和各自的使用场景。以下是它们的主要区别和各自特点:
type 类型
-
定义基本类型别名:
type Name = string; type Age = number; -
联合类型和交叉类型:
type StringOrNumber = string | number; type Person = { name: string } & { age: number }; -
复杂类型定义:
type User = { name: string; age: number; isActive: boolean; }; -
映射类型:
type ReadonlyUser = Readonly<User>; -
元组:
type Point = [number, number];
interface 接口
-
对象类型定义:
interface User { name: string; age: number; isActive: boolean; } -
可扩展性: 接口可以被扩展(继承),使得复用和扩展更方便。
interface Employee extends User { salary: number; } -
合并声明: 同一个接口名的多个声明会自动合并。
interface User { address: string; } // 上面的 User 接口会合并为: interface User { name: string; age: number; isActive: boolean; address: string; }
主要区别
-
扩展性:
interface可以通过extends来扩展。type可以通过交叉类型(&)来组合,但不能直接扩展。
-
合并声明:
interface会自动合并同名接口的声明。type不会自动合并同名类型的声明。
-
使用场景:
- 如果需要定义一个对象类型并且可能需要扩展或多次声明时,使用
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)?
如下图,直接写空对象肯定是不行的。
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通过遍历这些属性名称,生成一个新的类型。?将这些属性标记为可选属性。
使用场景
-
函数参数:在不需要传递所有属性的情况下,可以使用
Partial让某些参数变为可选。function updateUser(user: Partial<User>) { // 可以只更新部分属性 } -
状态管理:在某些应用场景(如 React 状态管理)中,通常只需要更新部分状态值,用
Partial可以简化状态更新。const newState: Partial<AppState> = { isLoading: true };