面试题答案
一键面试1. 精确类型定义
- 避免过度宽泛类型:在大型项目中,使用精确的类型而不是宽泛类型,比如用
string
而不是any
。例如,若函数只接受特定格式的字符串,定义一个自定义类型:
type Email = string & { __brand: 'email' };
function sendEmail(to: Email, content: string) {
// 处理发送邮件逻辑
}
- 使用联合类型和交叉类型:对于函数参数可能接受多种类型时,使用联合类型。如一个函数可能接受数字ID或字符串ID:
type ID = string | number;
function getUserById(id: ID) {
// 获取用户逻辑
}
交叉类型用于合并多个类型的属性,如一个函数接受具有name
和age
属性的对象:
type Name = { name: string };
type Age = { age: number };
type Person = Name & Age;
function greet(person: Person) {
console.log(`Hello, ${person.name}, you are ${person.age} years old.`);
}
2. 类型别名与接口复用
- 类型别名抽取:将重复使用的复杂类型定义为类型别名。比如,一个函数接受包含多个属性的配置对象,将该对象类型抽取为别名:
type HttpConfig = {
url: string;
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
headers: { [key: string]: string };
};
function makeHttpCall(config: HttpConfig) {
// 发起HTTP请求逻辑
}
- 接口继承:当有多个相关的对象类型时,使用接口继承来复用和扩展类型。例如,有一个基础的用户信息接口,还有一个管理员用户接口继承自它:
interface User {
name: string;
email: string;
}
interface AdminUser extends User {
role: 'admin';
}
function displayUser(user: User) {
console.log(`Name: ${user.name}, Email: ${user.email}`);
}
function manageAdmin(admin: AdminUser) {
displayUser(admin);
console.log(`Admin Role: ${admin.role}`);
}
3. 泛型函数
- 参数化类型:对于通用逻辑的函数,使用泛型来避免重复定义。如一个获取数组中特定索引元素的函数:
function getElement<T>(arr: T[], index: number): T | undefined {
if (index >= 0 && index < arr.length) {
return arr[index];
}
return undefined;
}
let numbers = [1, 2, 3];
let num = getElement(numbers, 1);
let strings = ['a', 'b', 'c'];
let str = getElement(strings, 2);
- 约束泛型:有时候需要对泛型进行约束,确保其具有某些属性。比如,一个函数接受具有
length
属性的对象:
interface Lengthwise {
length: number;
}
function printLength<T extends Lengthwise>(arg: T) {
console.log(`Length of ${arg} is ${arg.length}`);
}
printLength('hello');
printLength([1, 2, 3]);
4. 类型推断与显式注解
- 合理利用类型推断:TypeScript 能够根据上下文推断类型,在简单场景下可减少显式注解。例如:
function add(a, b) {
return a + b;
}
let result = add(1, 2); // result 被推断为 number 类型
- 显式注解复杂参数:在参数类型复杂且不易推断时,显式添加注解,提高代码可读性和可维护性。如一个函数接受复杂的嵌套对象作为参数:
type Inner = { value: string };
type Outer = { inner: Inner[] };
function process(outer: Outer) {
// 处理逻辑
}
let data: Outer = { inner: [{ value: 'test' }] };
process(data);
5. 类型检查工具集成
- ESLint 与 TypeScript 结合:配置 ESLint 规则来强制类型检查。例如,使用
@typescript-eslint
插件,开启规则如@typescript-eslint/no-explicit-any
,防止使用any
类型。 - 构建工具集成:在构建过程中,利用TypeScript编译器的严格模式(如
strict: true
),确保类型错误在编译阶段被捕获,避免运行时错误,提升整体性能。