TypeScript 类型系统深入
TypeScript 是 JavaScript 的超集,通过静态类型系统为开发者提供了更好的开发体验和代码质量。本文将深入探讨 TypeScript 的类型系统核心概念和高级用法。
基础类型
1. 基本类型
let name: string = "TypeScript"; let age: number = 25; let isStudent: boolean = true; let empty: null = null; let notDefined: undefined = undefined;
let bigInt: bigint = 9007199254740991n; let symbol: symbol = Symbol("unique");
let numbers: number[] = [1, 2, 3]; let strings: Array<string> = ["a", "b", "c"];
let tuple: [string, number] = ["hello", 123];
enum Color { Red, Green, Blue }
const color: Color = Color.Red;
|
2. 对象类型
let person: { name: string; age: number; hobbies: string[]; } = { name: "Alice", age: 30, hobbies: ["reading", "coding"] };
interface Person { name: string; age?: number; readonly id: string; [key: string]: any; }
const person: Person = { name: "Bob", id: "123" };
|
3. 函数类型
function add(a: number, b: number): number { return a + b; }
const multiply: (a: number, b: number) => number = (a, b) => a * b;
const divide = (a: number, b: number): number => a / b;
function greet(name: string, greeting?: string): string { return `${greeting || "Hello"}, ${name}!`; }
function createPoint(x: number = 0, y: number = 0): { x: number; y: number } { return { x, y }; }
function sum(...numbers: number[]): number { return numbers.reduce((acc, curr) => acc + curr, 0); }
|
高级类型
1. 联合类型
let value: string | number; value = "hello"; value = 42;
type Direction = "up" | "down" | "left" | "right";
function move(direction: Direction): void { console.log(`Moving ${direction}`); }
function processValue(value: string | number): string { if (typeof value === "string") { return value.toUpperCase(); } return value.toString(); }
function getValue(): string | number { return Math.random() > 0.5 ? "hello" : 42; }
const result = getValue() as string;
|
2. 交叉类型
type Person = { name: string; age: number; };
type Employee = { id: string; department: string; };
type EmployeeWithPerson = Person & Employee;
const employee: EmployeeWithPerson = { name: "Alice", age: 30, id: "123", department: "Engineering" };
type Nullable<T> = T | null; type Optional<T> = T | undefined; type Maybe<T> = Nullable<Optional<T>>;
|
3. 泛型
function identity<T>(arg: T): T { return arg; }
const result1 = identity<string>("hello"); const result2 = identity(42);
function first<T>(array: T[]): T | undefined { return array[0]; }
function last<T>(array: T[]): T | undefined { return array[array.length - 1]; }
interface Lengthwise { length: number; }
function logLength<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }
logLength("hello"); logLength([1, 2, 3]); logLength({ length: 42 });
interface Container<T> { value: T; }
const numberContainer: Container<number> = { value: 123 }; const stringContainer: Container<string> = { value: "hello" };
|
4. 类型别名和映射类型
type Point = { x: number; y: number; };
type ID = string | number;
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
type Optional<T> = { [P in keyof T]?: T[P]; };
type User = { name: string; age: number; email: string; };
type ReadonlyUser = Readonly<User>; type PartialUser = Partial<User>; type OptionalUser = Optional<User>;
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type UserWithoutEmail = Omit<User, "email">; type UserNameAndAge = Pick<User, "name" | "age">;
|
5. 条件类型
type ExtractType<T, U> = T extends U ? T : never; type ExcludeType<T, U> = T extends U ? never : T;
type StringOrNumber = string | number; type StringOnly = ExtractType<StringOrNumber, string>; type NumberOnly = ExcludeType<StringOrNumber, string>;
type NonNullable<T> = T extends null | undefined ? never : T; type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any) => infer R ? R : any;
type ToArray<T> = T extends any ? T[] : never; type Str = ToArray<string>; type Num = ToArray<number>; type Both = ToArray<string | number>;
|
高级类型操作
1. 类型推断
let inferredArray = [1, 2, 3]; let inferredObject = { name: "Alice", age: 30 };
function map<T, U>(array: T[], fn: (item: T) => U): U[] { return array.map(fn); }
const numbers = [1, 2, 3]; const doubled = map(numbers, x => x * 2);
const complexObject = { name: "Alice", age: 30, address: { street: "123 Main St", city: "New York" } };
const street = complexObject.address.street;
|
2. 类型守卫
function isString(value: any): value is string { return typeof value === "string"; }
function processValue(value: string | number): string { if (isString(value)) { return value.toUpperCase(); } return value.toString(); }
class Animal { name: string; constructor(name: string) { this.name = name; } }
class Dog extends Animal { bark() { return "Woof!"; } }
function isDog(animal: Animal): animal is Dog { return "bark" in animal; }
interface Square { kind: "square"; size: number; }
interface Circle { kind: "circle"; radius: number; }
type Shape = Square | Circle;
function isSquare(shape: Shape): shape is Square { return shape.kind === "square"; }
|
3. 类型断言和类型收窄
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
function nonNullAssertion<T>(value: T): NonNullable<T> { return value!; }
type NetworkLoadedState = { state: "loaded"; data: any; };
type NetworkErrorState = { state: "error"; error: string; };
type NetworkState = NetworkLoadedState | NetworkErrorState;
function handleNetworkState(state: NetworkState) { if (state.state === "loaded") { console.log(state.data); } else { console.error(state.error); } }
|
实用类型工具
1. 常用工具类型
interface User { name: string; age: number; email: string; }
type PartialUser = Partial<User>;
type RequiredUser = Required<User>;
type ReadonlyUser = Readonly<User>;
type UserRoles = Record<"admin" | "user" | "guest", string>;
type UserName = Pick<User, "name">;
type UserWithoutEmail = Omit<User, "email">;
type Extracted = Extract<string | number | boolean, string>;
type Excluded = Exclude<string | number | boolean, string>;
|
2. 自定义工具类型
type DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]; };
interface NestedObject { name: string; address: { street: string; city: string; }; }
type DeepPartialNested = DeepPartial<NestedObject>;
type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]; };
type Paths<T> = T extends object ? { [K in keyof T]: K | `${K}.${Paths<T[K]>}`; }[keyof T] : never;
interface Nested { a: number; b: { c: string; d: { e: boolean; }; }; }
type NestedPaths = Paths<Nested>;
type OptionalFunction<T extends (...args: any[]) => any> = ( ...args: Parameters<T> ) => ReturnType<T>;
function process(value: string): string; function process(value: number): number; function process(value: string | number): string | number { if (typeof value === "string") { return value.toUpperCase(); } return value * 2; }
|
类型系统最佳实践
1. 类型设计原则
interface User { id: string; name: string; email: string; role: "admin" | "user" | "guest"; }
interface User { id: string | number; name: string; email?: string; role: any; }
interface Animal { name: string; }
interface Bird extends Animal { fly(): void; }
interface Fish extends Animal { swim(): void; }
interface Bird { name: string; fly(): void; }
interface Fish { name: string; swim(): void; }
interface Container<T> { value: T; get(): T; set(value: T): void; }
class NumberContainer implements Container<number> { value: number; constructor(value: number) { this.value = value; } get(): number { return this.value; } set(value: number): void { this.value = value; } }
|
2. 错误处理和类型安全
class Result<T, E = Error> { constructor( public readonly ok: boolean, public readonly value?: T, public readonly error?: E ) {}
static success<T, E = Error>(value: T): Result<T, E> { return new Result(true, value); }
static failure<T, E = Error>(error: E): Result<T, E> { return new Result(false, undefined, error); }
map<U>(fn: (value: T) => U): Result<U, E> { if (this.ok) { return Result.success(fn(this.value!)); } return Result.failure(this.error!); } }
function fetchUser(id: number): Result<User, Error> { try { const user = { id, name: "Alice" }; return Result.success(user); } catch (error) { return Result.failure(error as Error); } }
const result = fetchUser(1); result.map(user => user.name.toUpperCase());
|
3. 性能优化
function processData(data: { name: string; age: number; email: string }) { }
interface User { name: string; age: number; email: string; }
function processData(data: User) { }
type UserPreferences = { theme: "light" | "dark"; language: "en" | "zh" | "ja"; notifications: boolean; fontSize: number; };
type UserPreferencesPartial = Partial<UserPreferences>; type UserPreferencesRequired = Required<UserPreferences>; type UserPreferencesReadonly = Readonly<UserPreferences>;
|
实际应用场景
1. API 响应类型定义
interface ApiResponse<T> { data: T; success: boolean; message?: string; timestamp: Date; }
interface User { id: string; name: string; email: string; avatar?: string; }
async function fetchUsers(): Promise<ApiResponse<User[]>> { const response = await fetch('/api/users'); return response.json(); }
fetchUsers().then(response => { if (response.success) { const users = response.data; console.log(users.map(user => user.name)); } });
|
2. 状态管理类型
interface AppState { user: User; posts: Post[]; loading: boolean; error: string | null; }
interface Action { type: string; payload?: any; }
function reducer(state: AppState, action: Action): AppState { switch (action.type) { case 'SET_USER': return { ...state, user: action.payload }; case 'SET_LOADING': return { ...state, loading: action.payload }; case 'SET_ERROR': return { ...state, error: action.payload }; default: return state; } }
function isUserAction(action: Action): action is { type: 'SET_USER'; payload: User } { return action.type === 'SET_USER'; }
function isSetErrorAction(action: Action): action is { type: 'SET_ERROR'; payload: string } { return action.type === 'SET_ERROR'; }
function dispatch<T extends Action>(action: T): void { const newState = reducer(state, action); }
|
3. 组件属性类型
interface ButtonProps { children: React.ReactNode; variant?: "primary" | "secondary" | "danger"; size?: "small" | "medium" | "large"; onClick?: () => void; disabled?: boolean; className?: string; }
const Button: React.FC<ButtonProps> = ({ children, variant = "primary", size = "medium", onClick, disabled = false, className = "" }) => { const classes = `btn btn-${variant} btn-${size} ${disabled ? 'disabled' : ''} ${className}`; return ( <button className={classes} onClick={onClick} disabled={disabled} > {children} </button> ); };
const App: React.FC = () => { return ( <div> <Button variant="primary" onClick={() => console.log('Clicked')}> Click Me </Button> <Button variant="danger" disabled> Disabled Button </Button> </div> ); };
|
总结
TypeScript 的类型系统非常强大,掌握它可以带来以下好处:
- 类型安全:在编译时发现错误,减少运行时错误
- 代码可读性:清晰的类型定义让代码更容易理解
- 开发体验:IDE 提供智能提示和自动补全
- 重构支持:类型安全的重构
关键要点:
- 善用基础类型和高级类型
- 理解类型推断和类型守卫
- 创建可复用的工具类型
- 遵循类型设计原则
- 在实际项目中灵活应用
通过合理使用 TypeScript 的类型系统,可以构建更加健壮、可维护的应用程序。