TypeScript 泛型进阶:条件类型、映射类型与实战应用

一、泛型基础回顾

TypeScript
function identity<T>(value: T): T {
  return value
}

const n = identity<number>(42)
const s = identity('hello')   // 类型推断为 string

二、泛型约束

TypeScript
interface HasLength {
  length: number
}

function logLength<T extends HasLength>(arg: T): number {
  return arg.length
}

logLength('abc')      // ✅
logLength([1,2,3])    // ✅
logLength(123)        // ❌ number 没有 length

三、keyof 与索引访问

TypeScript
interface User {
  id: number
  name: string
  email: string
}

type UserKeys = keyof User   // 'id' | 'name' | 'email'
type NameType = User['name'] // string

四、条件类型

TypeScript
type IsString<T> = T extends string ? true : false

type A = IsString<'abc'>   // true
type B = IsString<123>     // false

// 实用:提取数组元素类型
type Flatten<T> = T extends Array<infer Item> ? Item : T

type C = Flatten<string[]>   // string
type D = Flatten<number>     // number

五、infer 的高级用法

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

// 获取 Promise 结果类型
type Awaited<T> = T extends Promise<infer U> ? U : T

// 获取函数第一个参数
type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never

六、映射类型

TypeScript
// 全部可选
type Partial<T> = {
  [P in keyof T]?: T[P]
}

// 全部只读
type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

// 自定义:全部变为 string
type Stringify<T> = {
  [P in keyof T]: string
}

// 加修饰符(移除可选/只读)
type Mutable<T> = {
  -readonly [P in keyof T]-?: T[P]
}

七、实战案例一:类型安全的 API 请求

TypeScript
interface ApiMap {
  '/api/user': { id: number }
  '/api/article': { page: number; size: number }
  '/api/comment': { articleId: number }
}

type Path = keyof ApiMap

async function request<T extends Path>(
  path: T,
  params: ApiMap[T]
): Promise<unknown> {
  return fetch(path, {
    method: 'POST',
    body: JSON.stringify(params)
  }).then(r => r.json())
}

// 参数类型自动推导,传错就报错
request('/api/user', { id: 1 })       // ✅
request('/api/user', { page: 1 })     // ❌

八、实战案例二:表单校验类型

TypeScript
type Validator<T> = {
  [K in keyof T]?: (value: T[K]) => string | null
}

const userValidators: Validator<User> = {
  name: (v) => v.length > 0 ? null : '姓名必填',
  email: (v) => v.includes('@') ? null : '邮箱格式错误'
}

九、实战案例三:模板字面量类型

TypeScript
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type ApiRoute = '/user' | '/article' | '/comment'

type ApiKey = `${Lowercase<HttpMethod>}:${ApiRoute}`
// 'get:/user' | 'get:/article' | ... 共 12 种

十、工具类型速查

| 类型 | 作用 | | --- | --- | | Partial<T> | 全部可选 | | Required<T> | 全部必填 | | Readonly<T> | 全部只读 | | Pick<T, K> | 选取部分属性 | | Omit<T, K> | 排除部分属性 | | Record<K, V> | 构造字典类型 | | Exclude<T, U> | 排除联合类型成员 | | NonNullable<T> | 排除 null/undefined |
打赏作者 已有 0 人打赏,共 ¥0.00
我的打赏
前端小李同学
前端小李同学
Lv7 学习会员 原创 2 粉丝 737

Vue / React 双修,喜欢折腾工程化

  • 2文章
  • 3.7万总阅读
  • 1576获赞
  • 737粉丝

评论(0)

💬

还没有评论,来说两句吧