TypeScript学习笔记(10)-泛型

泛型的由来

如果想要创建可处理多种类型而不只是一种类型的组件,该怎么操作? 可以使用  any  类型,但这样就失去了 TypeScript 类型检查系统的功能。

泛型的特点

  • (「可复用行性」) 泛型是可以在代码库中定义和重复使用的代码模板。
  • (「定义时指示性」) 它们提供了一种方法,可用于指示函数、类或在调用接口时要使用的类型。
  • (「调用时指示性」) 可以通过将参数传递给函数的方式来理解,不同之处是使用泛型可以指示组件在被调用时应该使用哪种类型。

使用时机

当代码是满足以下条件的函数或类时,创建泛型函数:

  1. 处理各种数据类型。 在多个位置使用该数据类型。 泛型可以:
  • 在处理类型时提供更大的灵活性。
  • 实现代码重用。
  • 减少使用  any  类型的需要。

示例 :getArray  函数生成  any  类型的项的数组

// 使用any 传入任何参数 并返回任何参数
function getArray(items: any[]): any[] {
    return new Array().concat(items);
}

let numberArray = getArray([5, 10, 15, 20]);
let stringArray = getArray(['Cats''Dogs''Birds']);
numberArray.push(25);                       // OK
stringArray.push('Rabbits');                // OK
numberArray.push('This is not a number');   // OK
stringArray.push(30);                       // OK
console.log(numberArray);                   // [5, 10, 15, 20, 25, "This is not a number"]
console.log(stringArray);                   // ["Cats""Dogs""Birds""Rabbits", 30]

上面是 any 类型 没有类型检查等 ,如果想要在调用函数时确定数组将包含的值的类型,然后让 TypeScript 对传递给它的值进行类型检查以确保它们属于该类型,该怎么操作? 这时泛型就可以发挥作用了。

泛型函数定义

使用泛型重写  getArray  函数。 现在,它可以接受你在调用函数时指定的任何类型。

function getArray<T>(items: T[]): T[] {
return new Array<T>().concat(items);
}
  • 泛型定义一个或多个“类型变量”来标识要传递给组件的一个或多个类型(用尖括号 (< >) 括起来)
  • 函数中的类型变量称为。 T  是泛型的常用名称,但可以根据需要对其进行命名。
  • 指定类型变量后,可以使用它来代替参数类型、返回类型或将其置于函数中要添加类型批注的任何其他位置。

调用泛型函数

若要调用函数并向其传递类型,请将    追加到函数名称。

  • 例如,getArray表示了

    1. 指示函数仅接受  number  值的数组
    2. 并返回  number  值的数组。
    3. 因为类型已指定为  number,所以 TypeScript 会预期将  number  值传递给函数,如果传递的是其他值,则会引发错误。
  1. 如果在调用函数时省略类型变量,TypeScript 将推断类型。 但是,这仅适用于简单数据。
  2. 如果传入数组或对象,会导致推断任何类型(any)并消除类型检查。
function getArray<T>(items: T[]): T[] {
return new Array<T>().concat(items);
}

let numberArray = getArray<number>([5, 10, 15, 20]);
numberArray.push(25); // OK
numberArray.push('This is not a number'); // 类型“string”的参数不能赋给类型“number”的参数。

let stringArray = getArray<string>(['Cats''Dogs''Birds']);
stringArray.push('Rabbits'); // OK
stringArray.push(30); // 类型“number”的参数不能赋给类型“string”的参数。

使用多个类型变量

泛型组件中并不是只能使用单个类型变量。

// 使用多个变量
function person11<T, U>(name: T, age: U): U {
    console.log(age);
    return age
}

let returnNumber = person11<string, number>('王大可1', 18);
let returnString = person11<string, string>('王大可2''28');
let returnBoolean = person11<string, boolean>('王大可3'true);

returnNumber = returnNumber * 100;   // OK
returnString = returnString * 100;   // 错误 算术运算左侧必须是 "any""number""bigint" 或枚举类型
returnBoolean = returnBoolean * 100; // 错误 算术运算左侧必须是 "any""number""bigint" 或枚举类型

使用泛型类型的方法和属性

  1. 上面的T,U 非常宽泛,导致无法再函数内部无法使用变量。
  2. 使用类型变量创建泛型组件时,只能使用每种类型可用的对象的属性和方法。
  3. 防止参数不兼容的操作引起错误。
function person11<T, U>(name: T, age: U): U {
    let result: T = name + name;    // Error 运算符“+”不能应用于类型“T”和“T”
    console.log(age);
    return age
}

使用泛型约束来限制类型

为了解决上面的问题故而限制类型变量的变量范围

  1. 自定义 type 声明为元组 然后使用自定义类型 extend 类型变量
  2. 类型限制为另一个对象的属性
//自定义 type 声明为元组
type LimitTypes = string | number;

function person11<T extends LimitTypes, U>(name: T, age: U): U {
    let result: T = name + name;    // Error 运算符“+”不能应用于类型“T”和“T”
    console.log(age);
    return age
}

// 类型限制为另一个对象的属性
function getPets<T, K extends keyof T>(pet: T, key: K) {
    return pet[key];
}

let pets1 = { cats: 4, dogs: 3, parrots: 1, fish: 6 };
let pets2 = { 1: "cats", 2: "dogs", 3: "parrots", 4: "fish" }

console.log(getPets(pets1, "fish"));  // 输出 6
console.log(getPets(pets2, "3"));     // Error 类型“"3"”的参数不能赋给类型“4 | 3 | 1 | 2”的参数。

对泛型使用类型保护

在上面的例子中 虽然限定了泛型类型 LimitTypes 但是还是不能执行操作,这时可以使用类型保护来处理逻辑。

function person11<T, U extends LimitTypes>(name: T, age: U) {
    // let result: T = name + name;    // Error 运算符“+”不能应用于类型“T”和“T”

    let result: LimitTypes = '';
    let typeValue: string = typeof age;

    if (typeof age === 'number') {           // Is it a number?
        result = age + age;                // OK
    } else if (typeof age === 'string') {    // Is it a string?
        result = age + age;                // OK
    }
    console.log(`年龄是 ${age} 类型是 ${typeValue} 返回是 ${result}`);

    console.log(age);
    return result
}

let returnNumber = person11<string, number>('王大可1', 18);
let returnString = person11<string, string>('王大可2''28');
  • 只能使用 typeof 类型保护来检查基元类型 string、number、bigint、function、boolean、symbol、object 和未定义类型。
  • 若要检查类的类型,请使用 instanceof 类型保护。


原文始发于微信公众号(王大可996):TypeScript学习笔记(10)-泛型

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/205211.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!