2026.01.01

TypeScript 高级类型详解

深入理解 TypeScript 的高级类型操作,掌握类型编程的核心概念和最佳实践

类型查询与操作

typeof 类型推导

typeof 操作符可以在类型上下文中使用,用于获取值的类型信息。这是 TypeScript 类型系统中非常实用的特性。

// 基础类型推导
let temp1 = 'hello world'
const temp2 = null
const temp3 = (a: string) => a.toUpperCase()

// 对象类型推导
const user = {
    name: '小明',
    age: 18,
    address: {
        province: '北京',
        city: '昌平'
    }
}

// 类型查询
type Temp1 = typeof temp1 // string
type Temp2 = typeof temp2 // null
type Temp3 = typeof temp3 // (a: string) => string
type User = typeof user // 完整的对象类型
type UserName = typeof user.name // string

💡 tipstypeof 在类型位置使用时,推导的是编译时类型,而非运行时值。

索引访问类型 TK

使用索引访问类型可以精确获取对象类型中特定 key 对应的类型。

interface User {
    age: number
    name: string
    id: string
}

// 基础访问
type Age = User['age'] // number
type Name = User['name'] // string

// 联合类型访问
type AgeOrName = User['age' | 'name'] // string | number

// 数组元素类型访问
const colors = ['red', 'green', 'blue']
type Color = typeof colors[number] // string

// 配合 as const 使用
const roles = ['Admin', 'User', 'Guest'] as const
type Role = typeof roles[number] // 'Admin' | 'User' | 'Guest'

// 嵌套访问
interface NestedObj {
    user: {
        name: string
        age: number
    }
    settings: {
        theme: 'light' | 'dark'
        language: string
    }
}

type UserName = NestedObj['user']['name'] // string
type Theme = NestedObj['settings']['theme'] // 'light' | 'dark'

💡 tips:使用 as const 可以将数组转换为具体的字面量联合类型,实现更严格的类型控制。


键值操作

keyof 操作符

keyof 是类型系统的"反射"操作符,可以获取类型所有键的联合类型。

interface User {
    id: number
    name: string
    age: number
}

// 获取所有键的联合类型
type UserKeys = keyof User // "id" | "name" | "age"

// 结合索引访问获取所有值的联合类型
type UserValues = User[keyof User] // string | number

// 实际应用
type RequiredKey = keyof User // 必填字段
type OptionalKey = keyof Partial<User> // 可选字段

in 操作符

in 操作符用于映射类型,可以遍历联合类型的每个成员。

// 基础用法
type Keys = 'name' | 'age' | 'id'

// 创建映射类型
type User = {
    [key in Keys]: string
}
// type User = {
//   name: string;
//   age: string;
//   id: string;
// }

// 带条件映射
type OptionalUser = {
    [key in keyof User]?: User[key]
}
// type OptionalUser = {
//   name?: string;
//   age?: string;
//   id?: string;
// }

索引签名

索引签名允许定义对象可以包含任意数量的属性。

// 基础索引签名
interface AnyObject {
    [key: string]: any
}

// 限制值类型
interface Config {
    [key: string]: string | number | boolean
}

// 键值类型受限
interface StrictConfig {
    [key: 'theme' | 'language']: string
}

// 使用示例
const user: Config = {
    name: '小明',
    age: 18,
    isActive: true
    // 可以动态添加新属性
}

⚠️ 使用索引签名时,所有显式声明的属性类型必须兼容索引签名的值类型。

索引签名 vs Record

Record<K, T> 是 TypeScript 内置的工具类型,作用类似于索引签名,但更简洁。

// 索引签名方式
interface User1 {
    [key: string]: string
}

// Record 方式
type User2 = Record<string, string>

// 实际应用场景
type Roles = Record<'admin' | 'user' | 'guest', string[]>
const rolePermissions: Roles = {
    admin: ['read', 'write', 'delete'],
    user: ['read'],
    guest: []
}

条件类型

条件类型是 TypeScript 的"三元运算符",允许基于类型条件返回不同的类型。

基础语法

// 基础条件类型
type IsString<T> = T extends string ? true : false

type Test1 = IsString<'hello'> // true
type Test2 = IsString<number> // false
type Test3 = IsString<string> // true

分布式条件类型

当条件类型与联合类型结合使用时,会触发分布式行为。

type ExtractString<T> = T extends string ? T : never

type Union = 'a' | 'b' | 'c'
type StringsOnly = ExtractString<Union> // 'a' | 'b' | 'c'

// 工作原理相当于:
// 'a' extends string ? 'a' : never    // 'a'
// 'b' extends string ? 'b' : never    // 'b'
// 'c' extends string ? 'c' : never    // 'c'
// 最终结果:'a' | 'b' | 'c'

实用工具类型实现

// 1. Extract - 提取联合类型中的部分
type MyExtract<T, U> = T extends U ? T : never

type A = 'a' | 'b' | 'c'
type B = 'a' | 'c'
type C = MyExtract<A, B> // 'a' | 'c'

// 2. Exclude - 排除联合类型中的部分
type MyExclude<T, U> = T extends U ? never : T

type D = MyExclude<A, B> // 'b'

// 3. NonNullable - 排除 null 和 undefined
type MyNonNullable<T> = T extends null | undefined ? never : T

type E = MyNonNullable<string | null | number> // string | number

高级应用 - 类型合并

// 合并两个类型,后面的类型覆盖前面的同名属性
interface Foo {
    name: string
    age: string
    address?: string
}

interface Bar {
    age: number
    sex: string
}

type Merge<T, S> = {
    [P in keyof T | keyof S]: P extends keyof S
        ? S[P]
        : P extends keyof T
            ? T[P]
            : never
}

type Result = Merge<Foo, Bar>
// type Result = {
//   name: string;
//   age: number;
//   address?: string;
//   sex: string;
// }

infer 类型推断

infer 关键字可以在条件类型中声明泛型变量进行类型推断。

数组操作

// 获取数组第一个元素类型
type First<T extends any[]> = T extends [] ? never : T[0]

type Array1 = ['a', 'b', 'c']
type First1 = First<Array1> // 'a'

type Array2 = []
type First2 = First<Array2> // never

// 获取数组最后一个元素类型
type Last<T extends any[]> = T extends [...infer Rest, infer Last]
    ? Last
    : never

type Last1 = Last<Array1> // 'c'

// 获取数组除第一个元素外的类型
type Rest<T extends any[]> = T extends [infer First, ...infer Rest]
    ? Rest
    : never

type Rest1 = Rest<Array1> // ['b', 'c']

函数类型推断

// 获取函数返回值类型
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never

type Func1 = (a: string) => number
type Func2 = () => string

interface Func3 {
    name: string
}

type Return1 = GetReturnType<Func1> // number
type Return2 = GetReturnType<Func2> // string
type Return3 = GetReturnType<Func3> // never

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

type Params1 = GetParameters<Func1> // [a: string]
type Params2 = GetParameters<Func2> // []

Promise 类型推断

// 获取 Promise 的值类型
type UnpackPromise<T> = T extends Promise<infer P> ? P : never

type Promise1 = Promise<string>
type Promise2 = Promise<number[]>

type Unpack1 = UnpackPromise<Promise1> // string
type Unpack2 = UnpackPromise<Promise2> // number[]

枚举与常量枚举

枚举基础

枚举是一组命名常量的集合,让代码更具可读性。

enum Status {
    Success = 200,
    NotFound = 404,
    Error = 500,
    Other = 'other'
}

// 使用枚举
function checkStatus(status: Status) {
    if (status === Status.Success) {
        console.log('操作成功')
    }
}

console.log(Status.Success) // 200

枚举的特性

特性说明
既是类型也是值可以用于类型标注,也可以参与逻辑运算
生成运行时代码编译后会生成 IIFE(立即执行函数)
反向映射数字枚举支持从值到键的反向映射
// 数字枚举的反向映射
enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}

console.log(Direction.Up) // 1
console.log(Direction[1]) // "Up"

枚举编译结果

枚举在编译后会生成代码:

// 编译后的代码
let Status;
(function (Status) {
    Status[Status.Success = 200] = 'Success'
    Status[Status.NotFound = 404] = 'NotFound'
    Status[Status.Error = 500] = 'Error'
    Status[Status.Other = 'other'] = 'Other'
})(Status || (Status = {}))

推荐替代方案:常量对象

在现代 ESM 生态中,推荐使用 const 配合 as const 来替代枚举:

// 常量对象
const Status = {
    Success: 200,
    NotFound: 404,
    Error: 500,
    Other: 'other'
} as const

// 获取联合类型
type Status = typeof Status[keyof typeof Status]
// 200 | 404 | 500 | 'other'

// 使用
type StatusType = typeof Status[number] // 自动推断为联合类型

// 使用示例
function handleStatus(status: StatusType) {
    if (status === Status.Success) {
        console.log('操作成功')
    }
}

// 优势:可以被 tree-shaking 优化,保持类型安全

模板字符串类型

模板字符串类型允许你基于字符串字面量类型进行类型组合。

基础用法

type Direction = 'left' | 'right' | 'top' | 'bottom'
type BoxName = 'padding' | 'margin'

// 组合类型
type BoxModel = `${BoxName}-${Direction}`
// "padding-left" | "padding-right" | "padding-top" | "padding-bottom"
// | "margin-left" | "margin-right" | "margin-top" | "margin-bottom"

// 实际应用
type CSSProperties = {
    [key in BoxModel]: string
}

const styles: CSSProperties = {
    'padding-left': '10px',
    'margin-top': '20px'
    // ...
}

高级应用 - 动态属性名

interface User {
    name: string
    age: number
}

// 添加 getter 和 setter 方法
type AddGetter<T> = {
    [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K]
}

type AddSetter<T> = {
    [K in keyof T as `set${Capitalize<K & string>}`]: (value: T[K]) => void
}

type UserWithAccessors = AddGetter<User> & AddSetter<User>
/*
type UserWithAccessors = {
  getName: () => string;
  getAge: () => number;
  setName: (value: string) => void;
  setAge: (value: number) => void;
}
*/

// 使用示例
const user: UserWithAccessors = {
    name: '小明',
    age: 18,
    getName() {
        return this.name
    },
    getAge() {
        return this.age
    },
    setName(value) {
        this.name = value
    },
    setAge(value) {
        this.age = value
    }
}

模板字面量类型修饰符

// Uppercase - 转换为大写
type Event = `on${Capitalize<'click' | 'hover' | 'focus'>}`
// "onClick" | "onHover" | "onFocus"

// Lowercase - 转换为小写
type Method = `get${Uppercase<'user' | 'post' | 'config'>}`
// "getUser" | "getPost" | "getConfig"

// 模板字面量中的模式匹配
type ExtractFirst<T> = T extends `${infer First}${infer Rest}` ? First : never
type ExtractRest<T> = T extends `${infer First}${infer Rest}` ? Rest : never

type Test1 = ExtractFirst<'hello'> // 'h'
type Test2 = ExtractRest<'hello'> // 'ello'

类型递归

类型递归是 TypeScript 类型系统中最强大的特性之一,可以处理复杂的类型变换。

字符串转联合类型

// 将字符串的每个字符转为联合类型
type StringToUnion<T extends string> = T extends `${infer First}${infer Rest}`
    ? First | StringToUnion<Rest>
    : never

type Letters = StringToUnion<'abc'>
// 'a' | 'b' | 'c'

// 实际应用 - 路径解析
type PathToUnion<T extends string> = T extends `${infer First}/${infer Rest}`
    ? First | PathToUnion<Rest>
    : T

type Paths = PathToUnion<'home/user/profile'>
// 'home' | 'user' | 'profile'

深度可选类型

// 将对象的所有嵌套属性变为可选
type DeepPartial<T> = {
    [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}

interface User {
    name: string
    address: {
        street: string
        city: string
        country: string
    }
    hobbies: string[]
}

type PartialUser = DeepPartial<User>
/*
type PartialUser = {
  name?: string | undefined;
  address?: {
      street?: string | undefined;
      city?: string | undefined;
      country?: string | undefined;
  } | undefined;
  hobbies?: string[] | undefined;
}
*/

深度只读类型

// 将对象的所有嵌套属性变为只读
type DeepReadonly<T> = {
    readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}

type ReadonlyUser = DeepReadonly<User>
/*
type ReadonlyUser = {
  readonly name: string;
  readonly address: {
      readonly street: string;
      readonly city: string;
      readonly country: string;
  };
  readonly hobbies: readonly string[];
}
*/

树形结构遍历

// 递归提取树节点的 ID
type ExtractIds<T> = T extends { id: infer Id }
    ? Id | ExtractIds<T extends Array<infer U> ? U : never>
    : never

interface TreeNode {
    id: string
    children?: TreeNode[]
}

type NodeIds = ExtractIds<TreeNode>
// string

type MultipleNodeIds = ExtractIds<TreeNode[]>
// string

常用工具类型实现

基础工具类型

Copy 复制类型

// 复制一个对象类型
type Copy<T extends object> = {
    [K in keyof T]: T[K]
}

interface User {
    name: string
    age: number
}

type CopiedUser = Copy<User> // 与 User 相同

Partial 可选属性

// 将所有属性变为可选
type MyPartial<T> = {
    [K in keyof T]?: T[K]
}

// 内部实现原理
interface User {
    name: string
    age: number
    email?: string
}

type OptionalUser = MyPartial<User>
/*
{
  name?: string;
  age?: number;
  email?: string;
}
*/

Readonly 只读属性

// 将所有属性变为只读
type MyReadonly<T> = {
    readonly [K in keyof T]: T[K]
}

// 内部实现原理
type ReadonlyUser = MyPartial<User>
/*
{
  readonly name: string;
  readonly age: number;
  readonly email?: string;
}
*/

选择性工具类型

Pick 挑选属性

// 从类型中挑选指定的属性
type MyPick<T, K extends keyof T> = {
    [P in K]: T[P]
}

// 内部实现原理
interface User {
    id: number
    name: string
    age: number
    email?: string
}

type UserInfo = MyPick<User, 'name' | 'age'>
/*
{
  name: string;
  age: number;
}
*/

Omit 排除属性

// 从类型中排除指定的属性
type MyOmit<T, K extends keyof any> = {
    [P in Exclude<keyof T, K>]: T[P]
}

// 等价于 Pick<T, Exclude<keyof T, K>>
type MyOmitAlternative<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

// 内部实现原理
interface User {
    id: number
    name: string
    age: number
    email?: string
}

type UserProfile = MyOmit<User, 'age' | 'email'>
/*
{
  id: number;
  name: string;
}
*/

Record 映射类型

// 基于键类型创建对象类型
type MyRecord<K extends string | number | symbol, V> = {
    [P in K]: V
}

// 内部实现原理
type Roles = 'admin' | 'user' | 'guest'
type RolePermissions = Record<Roles, string[]>
/*
{
  admin: string[];
  user: string[];
  guest: string[];
}
*/

过滤工具类型

Extract 提取类型

// 从联合类型中提取符合条件的类型
type MyExtract<T, U> = T extends U ? T : never

// 内部实现原理
type Status = 'success' | 'error' | 'pending' | 'loading'
type StatusResults = Extract<Status, 'success' | 'pending'>
// 'success' | 'pending'

Exclude 排除类型

// 从联合类型中排除符合条件的类型
type MyExclude<T, U> = T extends U ? never : T

// 内部实现原理
type Status = 'success' | 'error' | 'pending' | 'loading'
type Errors = Exclude<Status, 'success' | 'pending'>
// 'error' | 'loading'

高级工具类型

Required 必填属性

// 将所有属性变为必填
type MyRequired<T> = {
    [P in keyof T]-?: T[P]
}

interface PartialUser {
    name?: string
    age?: number
}

type RequiredUser = MyRequired<PartialUser>
/*
{
  name: string;
  age: number;
}
*/

ReturnType 获取返回值类型

// 获取函数返回值的类型
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never

type Func1 = () => string
type Func2 = (x: number) => { success: boolean, data: any }

type Return1 = MyReturnType<Func1> // string
type Return2 = MyReturnType<Func2> // { success: boolean; data: any }

Parameters 获取参数类型

// 获取函数参数的类型
type MyParameters<T> = T extends (...args: infer P) => any ? P : never

type Func = (a: number, b: string) => boolean

type Params = MyParameters<Func> // [a: number, b: string]

工具类型速查表

工具类型作用使用场景
Partial<T>所有属性变为可选表单编辑、更新部分字段
Required<T>所有属性变为必填数据验证、确保完整性
Readonly<T>所有属性变为只读配置对象、常量定义
Pick<T, K>只保留指定属性筛选需要的字段
Omit<T, K>排除指定属性移除敏感字段、API响应处理
Record<K, V>基于键类型创建对象字典、映射表
Extract<T, U>提取联合类型中的部分类型过滤、条件判断
Exclude<T, U>排除联合类型中的部分类型过滤、错误类型排除
ReturnType<T>获取函数返回值类型异步处理、Promise链
Parameters<T>获取函数参数类型参数验证、函数重载

实战应用

1. API 响应类型处理

// API 响应基础类型
interface ApiResponse<T> {
    code: number
    message: string
    data: T
}

// 分页响应
interface PaginatedResponse<T> {
    items: T[]
    total: number
    page: number
    pageSize: number
}

// 自动提取 API 数据类型
type ApiData<T> = ApiResponse<T>['data']

// 使用示例
interface User {
    id: number
    name: string
    email: string
}

type UserResponse = ApiResponse<User>
type UserListResponse = PaginatedResponse<User>

// 获取用户数据的类型
type UserData = ApiData<UserResponse> // User
type UserListData = ApiData<UserListResponse> // PaginatedResponse<User>

// 自动处理 API 响应的工具
type ApiResponseHandler<T> = T extends ApiResponse<infer U>
    ? U
    : never

2. 组件 Props 类型推导

// 通用组件 Props 类型
interface BaseProps {
    className?: string
    style?: React.CSSProperties
    children?: React.ReactNode
}

// 状态组件 Props
interface StatefulProps<T> extends BaseProps {
    initialState: T
    onStateChange?: (state: T) => void
}

// 自动推导组件 Props
type ComponentProps<T> = T extends React.FC<infer P> ? P : never

// 使用示例
interface ButtonProps extends BaseProps {
    onClick: () => void
    disabled?: boolean
}

type ExtractedProps = ComponentProps<React.FC<ButtonProps>>
// ButtonProps

3. 路由参数类型推导

// 路由参数类型
type RouteParams<T extends string> = T extends `${string}:${infer Param}${infer Rest}`
    ? Param | RouteParams<Rest>
    : never

// 示例路由
type UserRoute = '/user/:id/profile'
type ProductRoute = '/product/:category/:id'

type UserParams = RouteParams<UserRoute> // 'id'
type ProductParams = RouteParams<ProductRoute> // 'category' | 'id'

// 动态路由生成
type CreatePath<T extends string, P extends Record<string, string>>
    = T extends `${string}:${infer Param}${infer Rest}`
    ? `${P[Param]}${CreatePath<Rest, P>}`
    : T

type UserPath = CreatePath<UserRoute, { id: '123' }>
// '/user/123/profile'

4. 状态管理类型增强

// Redux Action 类型
interface Action<T = any> {
    type: string
    payload?: T
}

// Reducer 类型
type Reducer<S, A extends Action = Action> = (state: S, action: A) => S

// 自动推导 Action 类型
type ActionType<T> = T extends Action<infer P> ? P : never

// 使用示例
interface UserAction extends Action<{ userId: number }> {
    type: 'SET_USER'
}

type UserActionPayload = ActionType<UserAction> // { userId: number }

5. 表单验证类型

// 表单规则类型
interface ValidationRule<T> {
    required?: boolean
    min?: number
    max?: number
    pattern?: RegExp
    custom?: (value: T) => boolean | string
}

// 表单字段类型
interface FormField<T> {
    value: T
    error?: string
    touched: boolean
}

// 表单类型
type Form<T> = {
    [K in keyof T]: FormField<T[K]>
}

// 表单验证工具
type ValidateForm<T> = (form: Form<T>) => { valid: boolean, errors: Partial<Record<keyof T, string>> }

// 使用示例
interface LoginForm {
    username: string
    password: string
    rememberMe: boolean
}

type LoginFormState = Form<LoginForm>

const validateLogin: ValidateForm<LoginForm> = (form) => {
    const errors: Partial<Record<keyof LoginForm, string>> = {}

    if (form.username.value.length < 3) {
        errors.username = '用户名至少3个字符'
    }

    if (form.password.value.length < 6) {
        errors.password = '密码至少6个字符'
    }

    return {
        valid: Object.keys(errors).length === 0,
        errors
    }
}

总结

TypeScript 的高级类型系统虽然复杂,但一旦掌握,就能编写出更加类型安全、更加优雅的代码。本文介绍的核心概念包括:

  1. 类型查询与操作:使用 typeof 和索引访问类型进行类型推导
  2. 键值操作:通过 keyofin 进行类型映射
  3. 条件类型:实现复杂的类型逻辑判断
  4. 类型推断:使用 infer 进行自动类型推导
  5. 枚举与常量:了解枚举的特性和替代方案
  6. 模板字符串类型:实现动态类型组合
  7. 类型递归:处理复杂的类型变换
  8. 工具类型:掌握常用工具类型的实现原理

通过实战应用示例,我们可以看到这些高级类型在实际开发中的强大作用。建议在学习过程中多实践,多思考,才能真正掌握 TypeScript 类型系统的精髓。