TypeScripts前端基础篇(3)--- 泛型详解

    泛型(Generics)是 TypeScript 中非常重要的特性,它允许我们创建可重用的组件,这些组件可以支持多种类型,而不会丢失类型安全性。
一、泛型基础
1. 基本概念
    泛型允许我们在定义函数、接口或类时不预先指定具体类型,而是在使用时再指定类型。
// 不使用泛型
function identity(arg: number): number {
  return arg;
}

// 使用泛型
function identity<T>(arg: T): T {
  return arg;
}
2. 泛型变量

function loggingIdentity<T>(arg: T[]): T[] {
  console.log(arg.length); // Array有length属性
  return arg;
}
二、泛型类型
1. 泛型函数

function identity<T>(arg: T): T {
  return arg;
}

// 两种调用方式
let output1 = identity<string>("myString"); // 显式指定类型
let output2 = identity("myString"); // 类型推断
2. 泛型接口

interface GenericIdentityFn<T> {
  (arg: T): T;
}

function identity<T>(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;
3. 泛型类

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

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;
三、泛型约束
1. 基本约束

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}
2. 在泛型约束中使用类型参数

function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

let x = { a: 1, b: 2, c: 3 };
getProperty(x, "a"); // 正确
getProperty(x, "m"); // 错误:m不是x的属性
四、高级泛型技巧
1. 泛型默认类型

interface DefaultGeneric<T = string> {
  value: T;
}

const a: DefaultGeneric = { value: "hello" }; // T默认为string
const b: DefaultGeneric<number> = { value: 123 };
2. 条件类型

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

type A = IsString<string>; // true
type B = IsString<number>; // false
3. 映射类型

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

type Partial<T> = {
  [P in keyof T]?: T[P];
};
五、常见内置泛型工具
1. Partial<T>
将所有属性变为可选:


interface Todo {
  title: string;
  description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}
2. Required<T>
将所有属性变为必选:


interface Props {
  a?: number;
  b?: string;
}

const obj: Required<Props> = { a: 5, b: "hello" };
3. Readonly<T>
将所有属性变为只读:


interface Todo {
  title: string;
}

const todo: Readonly<Todo> = { title: "Delete inactive users" };
todo.title = "Hello"; // 错误:无法分配到"title",因为它是只读属性
4. Record<K, T>
构造一个类型,其属性键为K,属性值为T:


interface CatInfo {
  age: number;
  breed: string;
}

type CatName = "miffy" | "boris" | "mordred";

const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};
5. Pick<T, K>
从类型T中选取一组属性K:


interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
6. Omit<T, K>
从类型T中排除一组属性K:


interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit<Todo, "description">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};
六、实际应用示例
1. API响应类型

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

// 用户数据
interface User {
  id: number;
  name: string;
}

// 使用
async function getUser(): Promise<ApiResponse<User>> {
  const response = await fetch("/api/user");
  return response.json();
}
2. 高阶组件

function withLoading<T>(WrappedComponent: React.ComponentType<T>) {
  return (props: T & { isLoading: boolean }) => {
    return props.isLoading ? <div>Loading...</div> : <WrappedComponent {...props} />;
  };
}
3. 状态管理

interface StoreState<T> {
  data: T[];
  loading: boolean;
  error: Error | null;
}

function createStore<T>(initialData: T[]): StoreState<T> {
  return {
    data: initialData,
    loading: false,
    error: null,
  };
}
七、常见问题
1. 什么时候使用泛型?
当函数、接口或类需要处理多种数据类型时

当需要保持输入与输出类型一致时

当需要基于已有类型创建更复杂的类型时

2. 泛型与any的区别
any 放弃了类型检查

泛型保持了类型约束,提供了更好的类型安全性

3. 如何限制泛型范围?
使用 extends 关键字:


function process<T extends string | number>(value: T): T {
  // ...
}
泛型是 TypeScript 中非常强大的特性,合理使用可以大大提高代码的可重用性和类型安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尔嵘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值