TypeScript泛型的艺术:编写类型安全的灵活代码
本文最后更新于 43 天前,其中的信息可能已经有所发展或是发生改变。

“泛型是TypeScript的类型体操,让静态类型拥有了动态表达能力”‌ —— TypeScript核心贡献者


1️⃣ 泛型基础

1.1 泛型函数

// 基础泛型函数
function identity<T>(arg: T): T {
  return arg;
}

// 自动类型推断
const output = identity("hello");  // 类型推断为string

// 显式指定类型
const num = identity<number>(100); // 明确指定number类型

1.2 泛型接口

interface GenericArray<T> {
  [index: number]: T;
  length: number;
}

const numberArray: GenericArray<number> = [1, 2, 3];
const stringArray: GenericArray<string> = ['a', 'b', 'c'];

1.3 泛型类

class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

const myNumber = new GenericNumber<number>();
myNumber.zeroValue = 0;
myNumber.add = (x, y) => x + y;

const myString = new GenericNumber<string>();
myString.zeroValue = "";
myString.add = (a, b) => a.concat(b);

2️⃣ 类型操作符

2.1 泛型约束

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // 现在可以安全访问length属性
  return arg;
}

2.2 条件类型

type NonNullable<T> = T extends null | undefined ? never : T;

type T0 = NonNullable<string | number | null>;  // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]

2.3 映射类型

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

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

type PartialPerson = Partial<Person>;
/* 等效于:
{
  name?: string;
  age?: number;
}
*/

3️⃣ 工程化实践

3.1 React组件Props泛型

interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function GenericList<T>({ items, renderItem }: ListProps<T>) {
  return (
    <div>
      {items.map((item, index) => (
        <div key={index}>{renderItem(item)}</div>
      ))}
    </div>
  );
}

// 使用示例
<GenericList
  items={[{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]}
  renderItem={(user) => <span>{user.name}</span>}
/>

3.2 API响应类型封装

interface ApiResponse<T = any> {
  code: number;
  data: T;
  message?: string;
}

type User = {
  id: string;
  name: string;
  email: string;
};

const fetchUsers = async (): Promise<ApiResponse<User[]>> => {
  const response = await fetch('/api/users');
  return response.json();
};

4️⃣ 高级模式

4.1 泛型递归

type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object 
    ? DeepReadonly<T[P]> 
    : T[P];
};

interface NestedObject {
  a: number;
  b: {
    c: boolean;
    d: {
      e: string;
    };
  };
}

type ReadonlyNested = DeepReadonly<NestedObject>;

4.2 类型推断

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

function getString() {
  return "hello";
}

type T1 = ReturnType<typeof getString>; // string

5️⃣ 性能优化

5.1 类型实例化深度限制

// 避免超过默认的50层嵌套限制
type Tuple<T, N extends number> = N extends N 
  ? number extends N 
    ? T[] 
    : _Tuple<T, N, []> 
  : never;

type _Tuple<T, N extends number, R extends unknown[]> = 
  R['length'] extends N ? R : _Tuple<T, N, [T, ...R]>;

5.2 类型缓存策略

interface Cache<T = any> {
  data: T;
  timestamp: number;
}

const createCache = <T>(initialData: T): Cache<T> => ({
  data: initialData,
  timestamp: Date.now()
});

// 使用示例
const numberCache = createCache<number>(42);
const userCache = createCache({ name: 'Alice' }); // 自动推断类型

最佳实践‌:

  1. 优先使用类型推断而不是显式注解
  2. 避免过度复杂的嵌套泛型
  3. 合理使用泛型约束保证类型安全
  4. 对公共API进行完整的泛型文档说明
  5. 定期进行类型性能分析

常见错误‌:

// 错误:不必要的泛型参数
function badExample<T>(arg: any): any { /*...*/ }

// 正确:明确泛型的使用场景
function goodExample<T>(arg: T): T { /*...*/ }

扩展资源‌:

欢迎在评论区分享你的泛型使用心得! 🚀

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇