TypeScript 泛型

TypeScript 泛型

TypeScript泛型是一种提供创建可重复使用组件的工具。它创建的组件可以与多种数据类型一起使用,而不是单一数据类型。它允许用户消费这些组件并使用自己的类型。泛型确保了长期使用中程序的灵活性和可伸缩性。

泛型提供了不损害性能或生产力的类型安全性。TypeScript使用类型变量来表示泛型函数中的类型。泛型函数的类型与非泛型函数相似,类型参数列在前面,类似于函数声明。

在泛型中,我们需要在尖括号(<)和封闭括号(>)之间写入类型参数,从而使其成为强类型的集合。泛型使用特殊类型变量<T>来表示类型。泛型集合只包含相似类型的对象。

在TypeScript中,我们可以创建泛型类、泛型函数、泛型方法和泛型接口。TypeScript泛型与C#和Java泛型几乎相似。

示例

以下示例帮助我们清楚地理解泛型。

function identity<T>(arg: T): T {  
    return arg;  
}  
let output1 = identity<string>("myString");  
let output2 = identity<number>( 100 );
console.log(output1);
console.log(output2);

当我们编译上述文件时,将返回下面的相应JavaScript文件。

function identity(arg) {
    return arg;
}
var output1 = identity("myString");
var output2 = identity(100);
console.log(output1);
console.log(output2);

输出:

TypeScript 泛型

泛型的优势

泛型主要有三个优势。它们如下:

  1. 类型安全: 只能在泛型中保存一种类型的对象,不允许保存其他类型的对象。
  2. 不需要类型转换: 不需要对对象进行类型转换。
  3. 编译时检查: 在编译时进行检查,因此问题不会在运行时出现。

为什么需要泛型

我们可以通过以下示例来理解泛型的需求。

function getItems(items: any[] ) : any[] {
    return new Array().concat(items);
}
let myNumArr = getItems([10, 20, 30]);
let myStrArr = getItems(["Hello", "JavaTpoint"]);
myNumArr.push(40); // Correct
myNumArr.push("Hello TypeScript"); // Correct
myStrArr.push("Hello SSSIT"); // Correct
myStrArr.push(40); // Correct
console.log(myNumArr); // [10, 20, 30, 40, "Hello TypeScript"]
console.log(myStrArr); // ["Hello", "JavaTpoint", "Hello SSSIT", 40]

输出:

TypeScript 泛型

在上面的示例中, getItems() 函数接收一个类型为 any 的数组。getItems()函数创建了一个类型为 any 的新数组,将项连接到它上面,并将这个新数组返回。由于我们使用了任意数据类型,我们可以传递任何类型的项给这个函数。但是,这可能不是添加项的正确方法。我们必须将 numbers 添加到 number数组 中,将 strings 添加到 string数组 中,但是我们不希望将数字添加到字符串数组中,反之亦然。

为了解决这个问题,TypeScript引入了泛型。在泛型中,类型变量只接受用户在声明时提供的特定类型。它还保留了类型检查信息。

因此,我们可以将上述函数写成以下泛型函数。

function getItems<T>(items : T[] ) : T[] {
    return new Array<T>().concat(items);
}
let arrNumber = getItems<number>([10, 20, 30]);
let arrString = getItems<string>(["Hello", "JavaTpoint"]);
arrNumber.push(40); // Correct
arrNumber.push("Hi! Javatpoint"); // Compilation Error
arrString.push("Hello TypeScript"); // Correct
arrString.push(50); // Compilation Error
console.log(arrNumber);
console.log(arrString);

输出:

TypeScript 泛型

泛型函数 getItems() 接受数字数组和字符串数组。当我们调用函数 getItems ([10, 20, 30]) ** ,它将使用number替换 **T 。因此,参数和返回值的类型将是数字数组。类似地,对于函数 getItems ([“Hello”, “JavaTpoint”]) ** ,参数类型和返回值将是字符串数组。现在,如果我们尝试在 **arrNumber 数组中添加一个字符串或在 arrString 中添加一个数字,编译器将显示错误。因此,它保留了类型检查的优势。

在TypeScript中,我们也可以在不指定类型变量的情况下调用泛型函数。TypeScript编译器将根据参数值的数据类型为函数设置T的值。

多类型变量

在TypeScript Generics中,我们可以使用不同的名称定义多类型变量。我们可以通过以下示例理解。

示例

function displayDataType<T, U>(id:T, name:U): void { 
  console.log("DataType of Id: "+typeof(id) + "\nDataType of Name: "+ typeof(name));  
}
displayDataType<number, string>(101, "Abhishek");

输出:

TypeScript 泛型

用非泛型类型的泛型

我们也可以将泛型类型与其他非泛型类型一起使用。

示例

function displayDataType<T>(id:T, name:string): void { 
  console.log("DataType of Id: "+typeof(id) + "\nDataType of Name: "+ typeof(name));  
}
displayDataType<number>(1, "Abhishek");

输出:

TypeScript 泛型

泛型类

TypeScript还支持泛型类。泛型类型参数在类名后的尖括号(<>)中指定。泛型类可以有泛型字段或方法。

示例

class StudentInfo<T,U>
{ 
    private Id: T;
    private Name: U;
    setValue(id: T, name: U): void { 
        this.Id = id;
        this.Name = name;
    }
    display():void { 
        console.log(`Id = {this.Id}, Name ={this.Name}`);
    }
}
let st = new StudentInfo<number, string>();
st.setValue(101, "Virat");
st.display();
let std = new StudentInfo<string, string>();
std.setValue("201", "Rohit");
std.display();

输出:

TypeScript 泛型

泛型接口

泛型类型也可以与接口一起使用。我们可以通过下面的示例理解泛型接口。

示例

interface People {
    name: string
    age: number
}
interface Celebrity extends People {
    profession: string
}
function printName<T extends Celebrity>(theInput: T): void {
    console.log(`Name: {theInput.name} \nAge:{theInput.age} \nProfession: ${theInput.profession}`);
}
let player: Celebrity = {
    name: 'Rohit Sharma', age: 30, profession: 'Cricket Player'
}
printName(player);

输出:

TypeScript 泛型

通用接口作为函数类型

我们也可以将通用接口用作函数类型。下面的示例可以理解它。

示例

interface StudentInfo<T, U>
{
    (id: T, value: U): void;
};
function studentData(id: number, value:string):void { 
    console.log('Id = '+ id + ', \nName = ' + value)
}
let std: StudentInfo<number, string> = studentData;
std(11, "Rohit Sharma");

TypeScript 泛型

通用约束

如我们所知,TypeScript的泛型类型允许与任何数据类型一起使用。然而,我们可以通过使用约束来限制它的类型。在下面的示例中,我们将创建一个具有 .length 属性的接口。我们将使用这个接口和 ” extends ” 关键字来表示我们的约束。

示例

interface Lengthwise {
    length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log("Length: " +arg.length);  // It has a .length property, so no more error found
    return arg;
}
loggingIdentity({length: 10, value: 9});
loggingIdentity(3);  // Compilation Error, number doesn't have a .length property

输出:

Length: 10
Length: undefined

完整控制类的泛型限定

下面给出了一个更高级的示例,展示了构造函数和类类型实例之间的泛型限定关系。

示例

class Student {
    Id: number;
    Name: string;

    constructor(id:number,  name:string) { 
        this.Id = id;
        this.Name = name;
    }
}
function display<T extends Student>(per: T): void {
    console.log(`{ st.Id}{st.Name}` );
}
var st = new Student(101, "\nVirat Kohli");
display(st);

输出:

TypeScript 泛型

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程