TypeScript高级类型深度解析

TypeScript高级类型深度解析

【免费下载链接】TypeScript TypeScript 使用手册(中文版)翻译。http://www.typescriptlang.org 【免费下载链接】TypeScript 项目地址: https://gitcode.com/gh_mirrors/typ/TypeScript

引言:为什么需要高级类型?

在日常的TypeScript开发中,我们经常会遇到基础类型无法满足的复杂场景。比如需要动态生成类型、基于现有类型创建新类型、或者处理复杂的类型关系。TypeScript的高级类型系统正是为了解决这些问题而生,它提供了强大的类型操作能力,让类型系统更加灵活和强大。

通过本文,你将掌握:

  • 🔥 交叉类型与联合类型的深度应用
  • 🚀 类型守卫与类型推断的实战技巧
  • 💡 映射类型与条件类型的核心原理
  • 🎯 模板字面量类型的创新用法
  • 📊 实用工具类型的完整指南
  • 🛠️ 真实项目中的高级类型最佳实践

一、交叉类型(Intersection Types)深度解析

交叉类型是将多个类型合并为一个类型,包含了所有类型的特性。这在混入(Mixins)模式和组合模式中特别有用。

1.1 基础交叉类型

interface Person {
  name: string;
  age: number;
}

interface Employee {
  employeeId: string;
  department: string;
}

type EmployeePerson = Person & Employee;

const john: EmployeePerson = {
  name: "John Doe",
  age: 30,
  employeeId: "EMP123",
  department: "Engineering"
};

1.2 交叉类型的实际应用场景

// 混入模式
function extend<First, Second>(first: First, second: Second): First & Second {
  const result: Partial<First & Second> = {};
  
  for (const prop in first) {
    if (first.hasOwnProperty(prop)) {
      (result as First)[prop] = first[prop];
    }
  }
  
  for (const prop in second) {
    if (second.hasOwnProperty(prop)) {
      (result as Second)[prop] = second[prop];
    }
  }
  
  return result as First & Second;
}

class Logger {
  log(message: string) {
    console.log(message);
  }
}

class User {
  constructor(public name: string) {}
}

const userWithLogger = extend(new User("Alice"), new Logger());
userWithLogger.log("Hello from extended user!");

1.3 交叉类型与接口继承的对比

特性交叉类型接口继承
合并方式类型合并接口扩展
同名属性必须兼容,否则为never可以重写
适用场景临时类型组合、混入明确的继承关系
可读性相对较低相对较高

二、联合类型(Union Types)与类型守卫

联合类型表示一个值可以是几种类型之一,配合类型守卫可以实现精确的类型控制。

2.1 基础联合类型

type Padding = string | number;

function padLeft(value: string, padding: Padding): string {
  if (typeof padding === 'number') {
    return ' '.repeat(padding) + value;
  }
  return padding + value;
}

2.2 类型守卫的四种方式

2.2.1 typeof 类型守卫
function processValue(value: string | number) {
  if (typeof value === 'string') {
    // value 被推断为 string
    return value.toUpperCase();
  } else {
    // value 被推断为 number
    return value.toFixed(2);
  }
}
2.2.2 instanceof 类型守卫
class FileHandler {
  read() { return "file content"; }
}

class NetworkHandler {
  fetch() { return "network data"; }
}

function handleResource(resource: FileHandler | NetworkHandler) {
  if (resource instanceof FileHandler) {
    return resource.read();
  } else {
    return resource.fetch();
  }
}
2.2.3 in 操作符类型守卫
interface Bird {
  fly(): void;
  layEggs(): void;
}

interface Fish {
  swim(): void;
  layEggs(): void;
}

function move(pet: Bird | Fish) {
  if ('fly' in pet) {
    pet.fly();
  } else {
    pet.swim();
  }
}
2.2.4 自定义类型守卫
function isFish(pet: Bird | Fish): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function handlePet(pet: Bird | Fish) {
  if (isFish(pet)) {
    pet.swim();  // TypeScript 知道 pet 是 Fish
  } else {
    pet.fly();   // TypeScript 知道 pet 是 Bird
  }
}

2.3 可辨识联合(Discriminated Unions)

interface Square {
  kind: 'square';
  size: number;
}

interface Rectangle {
  kind: 'rectangle';
  width: number;
  height: number;
}

interface Circle {
  kind: 'circle';
  radius: number;
}

type Shape = Square | Rectangle | Circle;

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'square':
      return shape.size * shape.size;
    case 'rectangle':
      return shape.width * shape.height;
    case 'circle':
      return Math.PI * shape.radius * shape.radius;
  }
}

三、映射类型(Mapped Types)深度探索

映射类型允许你基于旧类型创建新类型,是TypeScript中最强大的特性之一。

3.1 基础映射类型

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

3.2 映射类型实战应用

interface User {
  id: number;
  name: string;
  email: string;
  age?: number;
}

// 创建只读版本
type ReadonlyUser = Readonly<User>;

// 创建可选版本
type PartialUser = Partial<User>;

// 创建可为null的版本
type NullableUser = Nullable<User>;

// 选择特定属性
type UserPreview = Pick<User, 'id' | 'name'>;

// 排除特定属性
type UserWithoutEmail = Omit<User, 'email'>;

3.3 高级映射模式

// 映射修饰符控制
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

type Required<T> = {
  [P in keyof T]-?: T[P];
};

// 键重映射
type Getters<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

interface Person {
  name: string;
  age: number;
}

type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number; }

四、条件类型(Conditional Types)与类型推断

条件类型允许根据类型关系选择不同的类型,是构建复杂类型系统的核心。

4.1 基础条件类型

type TypeName<T> = T extends string
  ? 'string'
  : T extends number
  ? 'number'
  : T extends boolean
  ? 'boolean'
  : T extends undefined
  ? 'undefined'
  : T extends Function
  ? 'function'
  : 'object';

type T0 = TypeName<string>;      // "string"
type T1 = TypeName<42>;          // "number"  
type T2 = TypeName<true>;        // "boolean"
type T3 = TypeName<() => void>;  // "function"

4.2 分布式条件类型

type Diff<T, U> = T extends U ? never : T;
type Filter<T, U> = T extends U ? T : never;

type T4 = Diff<'a' | 'b' | 'c', 'a' | 'c'>;  // "b"
type T5 = Filter<'a' | 'b' | 'c', 'a' | 'c'>; // "a" | "c"

// 移除 null 和 undefined
type NonNullable<T> = Diff<T, null | undefined>;

4.3 infer 关键字与类型推断

// 提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

// 提取函数参数类型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

// 提取数组元素类型
type ElementType<T> = T extends (infer U)[] ? U : T;

// 提取Promise解析类型
type Awaited<T> = T extends Promise<infer U> ? U : T;

4.4 条件类型实战案例

// 深度可选类型
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// 深度只读类型
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

interface UserProfile {
  user: {
    name: string;
    address: {
      street: string;
      city: string;
    };
  };
  settings: {
    theme: string;
    notifications: boolean;
  };
}

type PartialUserProfile = DeepPartial<UserProfile>;
type ReadonlyUserProfile = DeepReadonly<UserProfile>;

五、模板字面量类型(Template Literal Types)

TypeScript 4.1引入的模板字面量类型为字符串操作提供了类型级别的支持。

5.1 基础模板字面量类型

type World = 'world';
type Greeting = `hello ${World}`;  // "hello world"

type EventName = 'click' | 'hover' | 'focus';
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onHover" | "onFocus"

5.2 高级模板类型应用

// 动态事件处理
type PropEventSource<T> = {
  on<K extends string & keyof T>(
    eventName: `${K}Changed`,
    callback: (newValue: T[K]) => void
  ): void;
};

function makeWatchedObject<T>(obj: T): T & PropEventSource<T> {
  // 实现略
  return obj as T & PropEventSource<T>;
}

const person = makeWatchedObject({
  firstName: 'John',
  lastName: 'Doe',
  age: 30
});

person.on('firstNameChanged', (newName) => {
  console.log(`First name changed to: ${newName}`);
});

person.on('ageChanged', (newAge) => {
  if (newAge < 0) throw new Error('Age cannot be negative');
});

5.3 字符串操作工具类型

// 内置字符串操作类型
type UppercaseStr = Uppercase<'hello'>;      // "HELLO"
type LowercaseStr = Lowercase<'HELLO'>;      // "hello"
type CapitalizedStr = Capitalize<'hello'>;   // "Hello"
type UncapitalizedStr = Uncapitalize<'Hello'>; // "hello"

// 自定义字符串模板工具
type Route<T extends string> = `/api/${Lowercase<T>}`;
type UserRoute = Route<'USERS'>;  // "/api/users"

type QueryString<T extends string> = `${T}=${string}`;
type SearchQuery = QueryString<'q'>;  // "q=string"

六、实用工具类型完整指南

TypeScript提供了丰富的内置工具类型,极大提高了开发效率。

6.1 常用工具类型速查表

工具类型描述示例
Partial<T>所有属性变为可选Partial<User>
Required<T>所有属性变为必需Required<User>
Readonly<T>所有属性变为只读Readonly<User>
Record<K, T>创建键类型为K的记录Record<string, number>
Pick<T, K>从T中选择属性KPick<User, 'name'>
Omit<T, K>从T中排除属性KOmit<User, 'id'>
Exclude<T, U>从T中排除可赋值给U的类型Exclude<string | number, string>
Extract<T, U>从T中提取可赋值给U的类型Extract<string | number, number>
NonNullable<T>排除null和undefinedNonNullable<string | null>
Parameters<T>获取函数参数类型Parameters<(a: number) => void>
ReturnType<T>获取函数返回类型ReturnType<() => string>
ConstructorParameters<T>获取构造函数参数类型ConstructorParameters<Error>
InstanceType<T>获取构造函数实例类型InstanceType<typeof Error>
ThisParameterType<T>获取this参数类型ThisParameterType<function>
OmitThisParameter<T>移除this参数OmitThisParameter<function>
ThisType<T>标记this类型ThisType<{ x: number }>

6.2 工具类型实战应用

// API响应类型处理
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

type ApiResponseData<T> = Pick<ApiResponse<T>, 'data'>;
type ApiError = Omit<ApiResponse<any>, 'data'>;

// 表单处理
interface UserForm {
  name: string;
  email: string;
  password: string;
  confirmPassword: string;
}

type UserRegistration = Pick<UserForm, 'name' | 'email' | 'password'>;
type UserLogin = Pick<UserForm, 'email' | 'password'>;

// 状态管理
interface AppState {
  user: User | null;
  loading: boolean;
  error: string | null;
}

type LoadingState = Pick<AppState, 'loading'>;
type ErrorState = Pick<AppState, 'error'>;
type UserState = Required<Pick<AppState, 'user'>>;

七、真实项目中的高级类型最佳实践

7.1 类型安全的API客户端

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

type ApiEndpoint<
  M extends HttpMethod,
  P extends Record<string, any>,
  R
> = {
  method: M;
  path: string;
  request: P;
  response: R;
};

type GetUserEndpoint = ApiEndpoint<
  'GET',
  { id: string },
  { user: User }
>;

type CreateUserEndpoint = ApiEndpoint<
  'POST',
  Omit<User, 'id'>,
  { user: User }
>;

// 类型安全的API调用函数
async function apiCall<E extends ApiEndpoint<any, any, any>>(
  endpoint: E['method'] extends 'GET' 
    ? Omit<E, 'request'> & { params: E['request'] }
    : E
): Promise<E['response']> {
  // 实现略
  return {} as E['response'];
}

// 使用示例
const user = await apiCall({
  method: 'GET',
  path: '/users',
  params: { id: '123' }
} as const);

7.2 高级表单验证类型

type ValidationRule<T> = {
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
  validate?: (value: T) => string | null;
};

type FormSchema<T> = {
  [K in keyof T]: ValidationRule<T[K]>;
};

type FormErrors<T> = {
  [K in keyof T]?: string;
};

type FormState<T> = {
  values: T;
  errors: FormErrors<T>;
  touched: Partial<Record<keyof T, boolean>>;
  isValid: boolean;
};

function createFormValidator<T>(schema: FormSchema<T>) {
  return (values: T): FormErrors<T> => {
    const errors: FormErrors<T> = {};
    
    for (const key in schema) {
      const rule = schema[key];
      const value = values[key];
      
      if (rule.required && !value) {
        errors[key] = '此字段为必填项';
      } else if (rule.minLength && typeof value === 'string' && value.length < rule.minLength) {
        errors[key] = `最少需要${rule.minLength}个字符`;
      } else if (rule.validate) {
        const customError = rule.validate(value);
        if (customError) errors[key] = customError;
      }
    }
    
    return errors;
  };
}

7.3 类型安全的Redux模式

// Action类型安全
type ActionType = string;
type ActionPayload = any;

type Action<T extends ActionType, P extends ActionPayload = void> = P extends void
  ? { type: T }
  : { type: T; payload: P };

type Actions = 
  | Action<'USER/LOGIN', { username: string; password: string }>
  | Action<'USER/LOGOUT'>
  | Action<'USER/UPDATE_PROFILE', Partial<User>>;

// 类型安全的reducer
function reducer(state: AppState, action: Actions): AppState {
  switch (action.type) {
    case 'USER/LOGIN':
      return { ...state, user: action.payload };
    case 'USER/LOGOUT':
      return { ...state, user: null };
    case 'USER/UPDATE_PROFILE':
      return { ...state, user: { ...state.user, ...action.payload } };
    default:
      return state;
  }
}

// 类型安全的action创建器
function createAction<T extends Actions['type']>(
  type: T,
  ...args: Extract<Actions, { type: T }> extends { payload: infer P }
    ? [P]
    : []
): Extract<Actions, { type: T }> {
  return args.length > 0 
    ? { type, payload: args[0] } as any
    : { type } as any;
}

// 使用示例
const loginAction = createAction('USER/LOGIN', {
  username: 'john',
  password: 'secret'
});

const logoutAction = createAction('USER/LOGOUT');

八、性能优化与最佳实践

8.1 类型性能考虑

// 避免深度嵌套的条件类型
// ❌ 性能较差
type DeepConditional<T> = T extends object
  ? { [K in keyof T]: DeepConditional<T[K]> }
  : T;

// ✅ 使用映射类型替代
type ShallowMapped<T> = {
  [K in keyof T]: T[K];
};

// 使用接口而非复杂类型别名
// ❌ 复杂类型别名
type ComplexType = {
  [K in string]: K extends `on${infer Event}` 
    ? (event: Event) => void 
    : string;
};

// ✅ 使用接口
interface BetterType {
  [key: string]: string | ((event: string) => void);
}

8.2 代码组织最佳实践

// 使用命名空间组织复杂类型
namespace UserTypes {
  export interface Base {
    id: number;
    name: string;
  }
  
  export interface WithEmail extends Base {
    email: string;
  }
  
  export type ApiResponse = Partial<WithEmail>;
}

// 使用类型模块化
// types/user.ts
export interface User { /* ... */ }
export type UserApi = { /* ... */ }

// types/product.ts  
export interface Product { /* ... */ }
export type ProductApi = { /* ... */ }

// 主文件
import type { User, UserApi } from './types/user';
import type { Product, ProductApi } from './types/product';

【免费下载链接】TypeScript TypeScript 使用手册(中文版)翻译。http://www.typescriptlang.org 【免费下载链接】TypeScript 项目地址: https://gitcode.com/gh_mirrors/typ/TypeScript

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值