TypeScript—— 泛型

基本使用

泛型使用尖括号 来表示,并在定义函数、类或接口时指定类型参数。

const city = <T>(item: T): T => {
  return item; // T类似一个变量保证入参和出参类型一致。
};

let result = city<number>(42);
let result2 = city<string>("Southern Wind");
console.log(result); // 42
console.log(result2); // Southern Wind

这里可能就有疑问了,为什么要用泛型?原因:泛型可以让我们在编写代码时更加灵活和可重用,同时也可以避免类型错误的发生。

const city = (item: number | string): number | string => {
  return item;
};

比如接受 number 和 string 多个类型的参数,我们可以使用泛型来解决这个问题

泛型类型

const reverse = <T>(array: T[]): T[] => {
  return array.reverse();
};

const arr: number[] = [1, 2, 3, 4, 5, 6];

const reversedArr = reverse(arr);
console.log(reversedArr); // (6) [6, 5, 4, 3, 2, 1]

let string: string[] = ["a", "b", "c", "d", "e"];
let reversedString = reverse(string);
console.log(reversedString); // (5) ["e", "d", "c", "b", "a"]

泛型类型允许我们创建可以适用于多种类型的类,类中的成员可以使用泛型类型进行声明和使用

多类型集合,泛型如何处理?

  1. 返回类型集合
const citys = <T, U>(item: T, msg: U): [T, U] => {
  return [item, msg];
};
console.log(citys<number, string>(123, "456"));
  1. 泛型接口
    可以写一个接口,把接口内的参数变为泛型
    例如:
interface IFromData<T, U, V> {
  data: T;
  msg: U;
  status: V;
  code: V;
}
const per = <T, U, V>(
  data: T,
  msg: U,
  status: V,
  code: V
): IFromData<T, U, V> => {
  let result: IFromData<T, U, V> = {
    data,
    msg,
    status,
    code,
  };
  return result;
};

let s = per<object, string, number>(
  { name: "Southern Wind", age: 18 },
  "欢迎",
  200,
  0
);
console.log(s);

请添加图片描述

常用操作符

:extends

用来约束泛型类型,比如我想写一个函数,用来检查对象中是否存在某个 key,如果存在则返回 true,否则返回 false,我们可以使用泛型约束来实现这个功能(此处后面会提到)

泛型约束可以用来限制泛型类型的范围,使其满足特定条件。

:keyof

用来获取对象的 key,比如我想写一个函数,用来获取对象的 key,我们可以使用泛型约束来实现这个功能

interface Person {
  name: string;
  age: number;
  isMarray: boolean;
}
type per1 = keyof Person; // string | number | boolean
class Stack<T> {
  private items: T;
  constructor(items: T) {
    this.items = items;
  }
  getItems(): T {
    return this.items;
  }
}
let stack = new Stack<number>(123332);
console.log(stack.getItems()); // 123332
let stack2 = new Stack<string>("Southern Wind");
console.log(stack2.getItems()); // Southern Wind

使用泛型参数,可以在类的定义中引入类型变量来表示未知的类型。这样我们就可以在类实例化时指定具体的类型,从而创建适用于不同类型数据的类的实例。

泛型约束

假设length属性是可以用的,那么我们使用函数输出参数长度就会出现问题

const indentify = <T>(args: T):T => {
    console.log(args.length);   // // 类型“T”上不存在
    return args;
}

indentify([1,2,3,4,5,6,7,8])

请添加图片描述

出现这个问题是因为ts不能识别T上是否存在某个属性,我们需要对其定义一个类型,类型变量为extends

interface ILength{
    length: number;
}

const indentify = <T extends ILength>(args: T):T => {
    console.log(args.length);  // 8
    return args;
}

indentify([1,2,3,4,5,6,7,8])

当然也可以这么操作

const indentify = <T>(args: T[]):T[] => {
    console.log(args.length);  // 8
    return args;
}
let arr = [1,2,3,4,5,6,7,8]
console.log(indentify(arr)); // [1, 2, 3, 4, 5, 6, 7, 8]

const indentify2 = <T>(args: Array<T>):Array<T> => {
    console.log(args.length);  // 8
    return args;
}
let arr2 = [9,10,11,12,13,14,15,16]

console.log(indentify2(arr2)); //  [9,10,11,12,13,14,15,16]

也可以通过keyof来确认对象上的键是否存在

interface IK {
    name: string;
    sex: string;
    age: number;
    address: string;
  }
  
  // 通过 keyof 操作符,我们就可以获取指定类型的所有键,之后我们可以对结合extends约束
  
  const indentify = <IPerson, K extends keyof IK>(obj: IK, key: K): IK[K] => {
    return obj[key];
  };
  
  // 使用 indentify 函数
  const person: IK = {
    name: "Alice",
    sex: "female",
    age: 30,
    address: "123 Main St"
  };
  const nameKey: keyof IK = "name";
  
  const nameValue = indentify(person, nameKey);
  console.log("Name:", nameValue);  // Name: Alice
  

确保属性是否存在

比如我想写一个获取对象长度的函数 getLength,但不是所有的对象都有 length 属性,所以我们需要使用泛型约束来确保传入的对象具有 length 属性

/* function getLength<T extends { length: number }>(obj: T): number {
    return obj.length; 或
} */
interface Length {
  length: number;
}
function getLength<T extends Length>(obj: T): number {
  return obj.length;
}

let obj = "Hello";
let obj2 = [1, 2, 3, 4, 5, 6];
console.log(getLength(obj)); // 5
console.log(getLength(obj2)); // 6

检查对象的 key

比如我想写一个函数,用来检查对象中是否存在某个 key,如果存在则返回 true,否则返回 false,我们可以使用泛型约束来实现这个功能

function hasKey<T extends object, K extends keyof T>(obj: T, key: K): boolean {
  return key in obj;
}

let obj3 = {
  name: "Southern Wind",
  age: 20,
  gender: "male",
};

console.log(hasKey(obj3, "name")); // true

泛型接口

使用泛型接口可以创建适用于多种类型的接口,接口中的成员可以使用泛型类型进行声明和使用

interface Transformers<T, U> {
  transform(input: T): U;
}

class StringToNumberTransformer implements Transformers<string, number> {
  transform(input: string): number {
    return parseFloat(input);
  }
}

let transformer = new StringToNumberTransformer();
let results = transformer.transform("3.14");
console.log(typeof results, results); // number 3.14
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Southern Wind

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

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

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

打赏作者

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

抵扣说明:

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

余额充值