TypeScript 基础
TypeScript 面试题整理
目录
- 基础类型与语法
- 接口与类型别名
- 类与继承
- 泛型
- 装饰器
- 模块与命名空间
- 类型推断与类型断言
- 工具类型与高级类型
- 实战场景题
1. 基础类型与语法
问题: TypeScript 中 any
、unknown
、never
的区别是什么?
答案:
any
表示任意类型,绕过类型检查。unknown
表示未知类型,使用时需类型断言或收窄。never
表示永不存在的值(如抛出错误或无限循环)。
代码示例:
let a: any = "hello";
a = 42; // 无错误 let b: unknown = "world";
if (typeof b === "string") { console.log(b.length); // 类型收窄后使用
} function error(): never { throw new Error("Oops");
}
2. 接口与类型别名
问题: interface
和 type
有何异同?
答案:
- 相同点:均可定义对象、函数等类型。
- 不同点:
interface
可合并声明(声明同名接口会自动合并)。type
可使用联合类型(|
)、交叉类型(&
)等高级特性。
代码示例:
interface User { name: string }
interface User { age: number } // 合并为 { name: string; age: number } type Person = { name: string } | { age: number }; // 联合类型
3. 类与继承
问题: TypeScript 中 public
、private
、protected
修饰符的作用?
答案:
public
:默认修饰符,任意位置可访问。private
:仅类内部可访问。protected
:类内部及子类可访问。
代码示例:
class Animal { protected name: string; constructor(name: string) { this.name = name; }
} class Dog extends Animal { bark() { console.log(`${this.name} barks!`); } // 可访问 protected
}
4. 泛型
问题: 泛型的作用?如何约束泛型参数?
答案:
- 泛型用于创建可复用的类型或函数,避免重复代码。
- 通过
extends
约束泛型范围(如T extends object
)。
代码示例:
function logLength<T extends { length: number }>(arg: T): void { console.log(arg.length);
} logLength("hello"); // 5
logLength([1, 2, 3]); // 3
5. 装饰器
问题: 类装饰器的执行顺序是什么?
答案:
装饰器从下到上执行(离类最近的先执行)。
代码示例:
function Deco1() { return () => console.log("Deco1"); }
function Deco2() { return () => console.log("Deco2"); } @Deco1()
@Deco2()
class MyClass {}
// 输出顺序: Deco2 → Deco1
6. 模块与命名空间
问题: namespace
和 module
的区别?
答案:
namespace
用于逻辑分组,需通过/// <reference>
或打包工具合并。module
(现为 ES Module)是文件级作用域,通过import/export
管理依赖。
7. 类型推断与类型断言
问题: as
和 <>
类型断言的差异?
答案:
- 功能相同,但
<>
语法在 JSX 中会产生歧义,推荐使用as
。
代码示例:
const value = "hello" as string;
// 等价于
const value = <string>"hello";
8. 工具类型与高级类型
问题: 实现一个 PartialByKeys<T, K>
,使 T
的 K
属性变为可选。
答案:
type PartialByKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; interface User { name: string; age: number; }
type PartialUser = PartialByKeys<User, "age">;
// 结果: { name: string; age?: number }
9. 实战场景题
问题: 如何用 TypeScript 实现一个安全的 axios 封装?
安装必要依赖
确保项目中已安装 axios
和 typescript
。若需处理环境变量,可安装 dotenv
:
npm install axios dotenv
npm install --save-dev @types/node @types/axios
定义基础请求配置
创建 src/api/http.ts
文件,定义基础配置和拦截器:
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';const http: AxiosInstance = axios.create({baseURL: process.env.API_BASE_URL || 'https://api.example.com',timeout: 10000,headers: { 'Content-Type': 'application/json' }
});
添加请求拦截器
在 http.ts
中继续扩展拦截逻辑:
http.interceptors.request.use((config: AxiosRequestConfig) => {const token = localStorage.getItem('authToken');if (token) config.headers.Authorization = `Bearer ${token}`;return config;
}, (error) => Promise.reject(error));
添加响应拦截器
处理响应数据和错误:
http.interceptors.response.use((response: AxiosResponse) => response.data,(error) => {if (error.response?.status === 401) {window.location.href = '/login';}return Promise.reject(error.response?.data || error.message);}
);
封装通用请求方法
在同一个文件中添加类型安全的请求方法:
export const get = <T>(url: string, config?: AxiosRequestConfig): Promise<T> => http.get(url, config);export const post = <T, D>(url: string, data?: D, config?: AxiosRequestConfig): Promise<T> => http.post(url, data, config);// 同理实现 put、delete 等方法
定义类型声明
创建 src/api/types.ts
定义响应结构:
export interface ApiResponse<T> {code: number;data: T;message?: string;
}
使用示例
在业务代码中调用封装后的方法:
import { get, post } from './http';
import { ApiResponse } from './types';interface User {id: string;name: string;
}const fetchUser = async (id: string): Promise<ApiResponse<User>> => get(`/users/${id}`);const createUser = async (user: Omit<User, 'id'>): Promise<ApiResponse<string>> =>post('/users', user);
错误处理增强
可扩展错误类型以区分网络错误和业务错误:
class ApiError extends Error {constructor(public code: number,message: string,public details?: unknown) {super(message);}
}// 在拦截器中抛出自定义错误
http.interceptors.response.use(null, (error) => {if (error.response) {throw new ApiError(error.response.data.code,error.response.data.message,error.response.data.details);}throw new Error('Network Error');
});
环境变量管理
通过 .env
文件管理不同环境的配置:
# .env.development
API_BASE_URL=http://localhost:3000/api
在 http.ts
中通过 dotenv
加载配置:
import 'dotenv/config';const http = axios.create({baseURL: process.env.API_BASE_URL
});
```### 安装必要依赖确保项目中已安装 `axios` 和 `typescript`。若需处理环境变量,可安装 `dotenv`:
```bash
npm install axios dotenv
npm install --save-dev @types/node @types/axios