TypeScript 终极实战指南:从类型体操到企业级应用
一、TypeScript 核心特性精要
1. 类型系统深度解析
// 高级类型示例
type User<T extends boolean> = {
id: T extends true ? string : number;
name: string;
age: number;
roles: Array<'admin' | 'user' | 'guest'>;
createdAt: Date;
updatedAt?: Date; // 可选属性
}
// 条件类型与泛型约束
type AdminUser = User<true>;
type NormalUser = User<false>;
// 实用工具类型
type UserPreview = Pick<User<true>, 'id' | 'name'>;
type UserOptional = Partial<User<false>>;
2. 类型体操挑战
// 实现一个深度Readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
}
// 实现函数柯里化类型
type Curry<F extends (...args: any[]) => any> =
F extends (first: infer A, ...rest: infer B) => infer R
? B extends []
? F
: (arg: A) => Curry<(...args: B) => R>
: never;
// 测试用例
const add = (a: number, b: number, c: number): number => a + b + c;
type CurriedAdd = Curry<typeof add>; // (arg: number) => (arg: number) => (arg: number) => number
二、工程化实践
1. 现代前端配置
// tsconfig.json 最佳实践
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "NodeNext",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vite/client"],
"outDir": "dist",
"declaration": true,
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
2. 类型定义管理策略
// 全局类型扩展示例
declare global {
interface Window {
__APP_CONFIG__: {
apiBaseUrl: string;
env: 'dev' | 'prod' | 'test';
};
}
// 为第三方库扩展类型
module 'lodash' {
interface LoDashStatic {
deepMapValues(obj: object, iteratee: Function): object;
}
}
}
// 类型守卫函数
function isError(value: unknown): value is Error {
return value instanceof Error;
}
// 类型断言函数
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== 'string') {
throw new Error('Not a string!');
}
}
三、React + TypeScript 最佳实践
1. 组件类型设计
// 泛型组件示例
interface ListProps<T> {
items: T[];
renderItem: (item: T, index: number) => React.ReactNode;
loading?: boolean;
emptyComponent?: React.ReactElement;
}
function List<T>({
items,
renderItem,
loading = false,
emptyComponent = <div>暂无数据</div>
}: ListProps<T>) {
if (loading) return <Spinner />;
if (!items.length) return emptyComponent;
return (
<ul className="list">
{items.map((item, index) => (
<li key={index}>{renderItem(item, index)}</li>
))}
</ul>
);
}
// 使用示例
<List<{ id: number; name: string }>
items={users}
renderItem={(user) => <span>{user.name}</span>}
/>
2. Redux Toolkit 类型安全
// store类型安全配置
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';
interface CounterState {
value: number;
status: 'idle' | 'loading' | 'failed';
}
const initialState: CounterState = {
value: 0,
status: 'idle'
};
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
});
export const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
// 推导RootState和AppDispatch类型
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
四、Node.js 后端开发
1. Express 类型安全路由
import express, { RequestHandler } from 'express';
import { ParamsDictionary } from 'express-serve-static-core';
interface User {
id: number;
name: string;
email: string;
}
// 自定义Request类型
interface CreateUserBody {
name: string;
email: string;
password: string;
}
const app = express();
app.use(express.json());
// 类型安全路由处理
app.post<ParamsDictionary, User, CreateUserBody>(
'/users',
async (req, res) => {
// req.body已自动推断为CreateUserBody
const newUser = await createUser(req.body);
res.status(201).json(newUser);
}
);
// 错误处理中间件
app.use(<RequestHandler<unknown, { error: string }>>(
(err: Error, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something broke!' });
}
));
2. Prisma 类型安全 ORM
// schema.prisma 模型定义
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// 类型安全CRUD操作
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function createUserWithPost(userData: {
email: string;
name?: string;
posts: {
title: string;
content?: string;
}[];
}) {
return prisma.user.create({
data: {
email: userData.email,
name: userData.name,
posts: {
create: userData.posts,
},
},
include: {
posts: true,
},
});
}
五、性能优化与高级技巧
1. 类型级性能优化
// 避免过度使用枚举
// 改为使用联合类型
type Status = 'active' | 'inactive' | 'pending';
// 使用const断言
const ROLES = ['admin', 'user', 'guest'] as const;
type Role = typeof ROLES[number]; // "admin" | "user" | "guest"
// 条件类型分发优化
type Filter<T, U> = T extends any
? T extends U
? T
: never
: never;
// 使用接口合并替代交叉类型
interface UserBase {
id: number;
}
interface UserWithName extends UserBase {
name: string;
}
2. 编译时类型检查
// 自定义类型保护
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string');
}
// 编译时断言
type Assert<T extends true> = T;
type IsString<T> = T extends string ? true : false;
type Test = Assert<IsString<'hello'>>; // 通过
// type ErrorTest = Assert<IsString<123>>; // 报错
// 品牌类型(Branded Types)
type UserId = string & { readonly brand: unique symbol };
type PostId = string & { readonly brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
function createPostId(id: string): PostId {
return id as PostId;
}
// 这样可以防止UserId和PostId混用
const userId: UserId = createUserId('123');
const postId: PostId = createPostId('456');
// const error: UserId = postId; // 类型错误
六、测试与调试
1. 类型测试工具
// 使用dtslint进行类型测试
// example.test-d.ts
import { expectType } from 'tsd';
declare const user: User<true>;
expectType<string>(user.id); // 通过
// expectType<number>(user.id); // 报错
// 使用@ts-expect-error测试类型错误
// @ts-expect-error
const error: string = 123; // 测试这里应该报错
// 运行时类型校验(io-ts示例)
import * as t from 'io-ts';
const User = t.type({
id: t.number,
name: t.string,
email: t.string,
});
type UserType = t.TypeOf<typeof User>; // 自动推导类型
const validateUser = (input: unknown): UserType => {
return User.decode(input).getOrElseL((errors) => {
throw new Error('Invalid user data');
});
};
七、前沿技术整合
1. WebAssembly 类型支持
// wasm类型定义
declare module '*.wasm' {
const url: string;
export default url;
}
// wasm-loader类型
interface WasmModule {
exports: {
add: (a: number, b: number) => number;
memory: WebAssembly.Memory;
};
}
declare function loadWasm(path: string): Promise<WasmModule>;
// 使用示例
async function useWasm() {
const wasm = await loadWasm('math.wasm');
console.log(wasm.exports.add(2, 3));
}
2. 类型安全的 GraphQL
// 使用TypeGraphQL
import { ObjectType, Field, ID, Resolver, Query, Arg } from 'type-graphql';
@ObjectType()
class User {
@Field(() => ID)
id!: number;
@Field()
name!: string;
@Field()
email!: string;
}
@Resolver(User)
class UserResolver {
@Query(() => User)
async user(@Arg('id') id: number): Promise<User> {
return getUserById(id);
}
}
// 自动生成的类型
type GetUserQuery = {
user: Pick<User, 'id' | 'name' | 'email'>;
};
通过系统学习TypeScript,开发者可以构建从简单脚本到企业级应用的全类型安全系统。建议的学习路径:
- 基础阶段:掌握类型系统与配置
- 进阶阶段:学习类型编程与工程化
- 专业方向:深入框架整合与性能优化
- 持续提升:参与DefinitelyTyped类型维护
关键实践原则:
- 优先使用类型推断而非显式注解
- 保持类型声明与实际实现同步
- 合理使用泛型避免重复代码
- 建立严格的类型边界检查
- 定期重构类型定义保持简洁