TypeScript系列:第三篇 - 泛型

上一篇 《TypeScript系列:续篇 - 对象类型(含数组、元数组、函数)》 中有提及对象类型中的"泛型"使用,本篇将详细展开...

TypeScript 引入泛型是为了增强代码的复用性、健壮性。

ts 复制代码
interface Box {
  contents: any;
}

interface Box<Type> {
  contents: Type;
}

泛型允许开发者编写一次代码,适用于多种数据类型,减少冗余。

其在编译时提供类型检查,提前发现错误,提高代码的健壮性。

定义

泛型(Generics)本质上是一种参数化类型。

在定义时不指定具体数据类型 ,用一个或多个占位符(通常用字母「如 TUV」)来表示类型参数;而在使用时指定具体的数据类型

ts 复制代码
function identity<T>(arg: T): T {
  return arg;
}

上述函数返回值的类型参数类型相关;可以接收任何类型的参数,并返回相同类型的值。

<T> 指类型参数,可以将其理解为类型声明需要的变量,在调用时传入具体的参数类型。

  • 调用时提供具体类型
ts 复制代码
identity<string>('ligang')
  • 省略不写,TypeScript 通常可以在泛型调用中推断出预期的类型参数。
ts 复制代码
identity('ligang') 

泛型写法

泛型可以在:函数、接口、类和别名 中定义。

泛型函数

定义一个泛型函数identity,它接受一个类型参数 T,并返回这个类型的值

ts 复制代码
function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>("ligang"); // 当然,这里的string可省略,Typescript会自行推断

泛型接口

定义了一个泛型接口 Lengthwise<T>,具有 length 属性和 value 属性,其中 length 是一个数字,而 value 是一个类型为T的值。

泛型函数 classArray ,接受一个类型为 Lengthwise<T> 的参数,并返回一个类型为 Lengthwise<T> 的值。

ts 复制代码
interface Lengthwise<T> {
  length: number;
  value: T;
}

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

classArray({ value: 'TypeScript', length: 10 });

泛型类

定义泛型类 Box<T> ,其构造函数接受一个类型参数 T 和一个参数 content,并将这个 content 赋值给类的私有属性 _content

ts 复制代码
class Box<T> {
  private _content: T;

  constructor(content: T) {
      this._content = content;
  }

  get content(): T {
      return this._content;
  }
}

const box = new Box<number>(123);

🐾 泛型别名

传入一个类型,得到这个类型与 undefinednull 的一个联合类型。

ts 复制代码
type Nullable<T> = T | undefined | null;

let a: Nullable<string> = 'ligang';
let b: Nullable<string> = null;
let c: Nullable<string>;
经典案例

泛型与别名的结合实现表格响应体的类型:

1️⃣ 响应结构体

ts 复制代码
interface Res<T> {
  status: 'success' | 'error';	// 状态码
  data: T;											// 返回数据
}

2️⃣ table 数据格式

ts 复制代码
interface TableData<T> {
  pageNumber: number;	// 页码
  pageSize: number;		// 每页条数
  total: number;			// 总条数
  data: T[];					// 表格数据
}

3️⃣ 结合:响应表格结构体

ts 复制代码
type ResTableData<T> = Res<TableData<T>>;
  • 这里的T 为表格数据类型

4️⃣ 调用示例

ts 复制代码
// 表格数据为 string
const tableData: ResTableData<string> = {
  status: 'success',
  data: {
    pageNumber: 1,
    pageSize: 10,
    total: 100,
    data: ['1', '2'],
  },
};

// 表格数据为 city
interface city {
  code: number;
  name: string;
}
const res: ResTableData<city> = {
  status: 'success',
  data: {
    pageNumber: 1,
    pageSize: 10,
    total: 100,
    data: [
      { code: 10010, name: '北京' },
      { code: 10011, name: '上海' },
    ],
  },
};

常见的泛型表示

类型 说明 示例
Array<T> T 可指定任何类型 let myAry: Array<number> = [1, 2, 3]
Map<K, V> KV 分别是键和值的类型参数,可指定任何类型 let myMap: Map<string, number> = new Map()
Set<T> T 可指定任何类型 let mySet: Set<number> = new Set([1, 2, 3])
Promise<T> T 可指定任何类型 let tableData = (): Promise<ResTableData<city>> => fetch('...').then((res) => res.json())
ts 复制代码
interface Array<Type> {
  length: number;
  pop(): Type | undefined;
  push(...items: Type[]): number;
  ...
}

泛型约束

如果需要限制泛型的使用范围,可以使用泛型约束!

ts 复制代码
<Type extends Constraint>

🌿 示例:提供一个获取对象属性的方法

ts 复制代码
function getProp<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

getProp({ name: 'ligang', age: '34' }, 'name'); 	 // 正确
getProp({ name: 'ligang', age: '34' }, 'address'); // 错误,address 对象中不存在

具体报错:类型""address""的参数不能赋给类型""name" | "age""的参数

keyof

keyof 是 TypeScript 中的关键字,用于从一个对象类型中提取所有键(属性名)的联合类型。

ts 复制代码
interface Person {
  name: string;
  age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'

✊ 综上,解释 getProp() ,只能获取对象既存的属性


除了使用 keyof 方式,也可以自定义约束条件~~

🍃 示例:限制必须有 length 属性

函数的作用:比较两个实现了 Len 接口的值的长度,并返回长度较大的那个值。

ts 复制代码
interface Len {
  length: number;
}
function compareLen<T extends Len, U extends Len>(a: T, b: U) {
  return a.length - b.length ? a : b;
}

compareLen([1, 2, 3], 'ab');

总结

泛型不仅提高了代码的可重用性和灵活性,同时也保证了类型的安全性。掌握好泛型的使用对于提升 TypeScript 编程技能至关重要!

相关推荐
胖方Hale1 小时前
04. Typescript 数组类型
前端·typescript
胖方Hale2 小时前
01. Typescript 基础数据类型
前端·typescript
Kjjia2 小时前
考试过程中校园网突然发力,答案没能保存...我炸了
前端·typescript
隐形喷火龙4 小时前
搭建TypeScript单元测试环境
javascript·typescript·单元测试
khalil18 小时前
浅析TS枚举与位运算的结合
前端·typescript
YuShiYue1 天前
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
javascript·vue.js·typescript·pnpm
前端极客探险家1 天前
前端 Excel 工具组件实战:导入 → 可编辑表格 → 导出 + 样式同步 + 单元格合并
前端·typescript·vue·excel
前端大白话2 天前
前端人速码!10个TypeScript神仙技巧,看完直接拿捏项目实战
前端·javascript·typescript
高木的小天才3 天前
鸿蒙中的并发线程间通信、线程间通信对象
前端·华为·typescript·harmonyos
_十六3 天前
看完就懂!用最简单的方式带你了解 TypeScript 编译器原理
前端·typescript