Javascript Typescript中泛型的常见用法是什么?
我试图了解在现实生活中,Typescript泛型通常用于什么,而不是在特殊情况下。我知道它为函数/类/接口添加了一个额外的抽象层,以便在不同的情况下重用它们,但我觉得您通常可以使用并集和交集类型来适应某种程度的通用性 但是,以下面的例子为例:Javascript Typescript中泛型的常见用法是什么?,javascript,typescript,typescript-generics,Javascript,Typescript,Typescript Generics,我试图了解在现实生活中,Typescript泛型通常用于什么,而不是在特殊情况下。我知道它为函数/类/接口添加了一个额外的抽象层,以便在不同的情况下重用它们,但我觉得您通常可以使用并集和交集类型来适应某种程度的通用性 但是,以下面的例子为例: 接口标识{ id1:V, id2:W } 函数标识(arg1:T,arg2:U):标识{ 让标识:标识={ id1:arg1, id2:arg2 }; 返回身份; } 所有这些都确保了无论参数具有何种类型,返回值都必须与这些类型匹配 我可以想象,如果您希
接口标识{
id1:V,
id2:W
}
函数标识(arg1:T,arg2:U):标识{
让标识:标识={
id1:arg1,
id2:arg2
};
返回身份;
}
所有这些都确保了无论参数具有何种类型,返回值都必须与这些类型匹配
我可以想象,如果您希望您的函数/类能够容纳各种不同的参数,但您唯一的限制是它们必须与某些方法兼容:
纵向接口{
长度:数字;
}
函数记录标识(arg:T):T{
console.log(arg.length);//现在我们知道它有一个.length属性,所以不再有错误了
返回arg;
}
这在某些情况下使用。泛型可用于存储来自API调用的附加数据,例如: API响应:
value: {} // this is generic
messages: [] // additional logging/errors/warnings
// other properties that apply for all objects
打字稿:
export interface GenericResponse<T> {
value: T;
messages: ApiMessageItem[];
// additional properties
}
导出接口通用响应{
值:T;
消息:ApiMessageItem[];
//附加属性
}
其中T是我从API调用的任何对象
您仍然可以使用联合来实现这一点,但我认为使用泛型更为简洁,尤其是使用50个不同的API对象。泛型的“计算机科学”术语是参数多态性,它实际上很好地说明了它们的用途。(好吧,如果你知道这是什么意思的话。)
那么,这意味着什么
好吧,让我们看看“参数化”的一般含义。这只是意味着我们可以有参数。我想我们都同意参数是有用的。一个只能添加3和5的函数非常无聊。一个函数,可以将任何数字添加到任何数字中,并且可以对这些数字进行参数化,现在这更有用了
类型构造函数(泛型类型在计算机科学中被称为类型构造函数)从另一个类型构造一个类型。之所以选择“类型构造函数”这个名称,是因为在数学的某些分支中,函数实际上被称为“构造函数”或“值构造函数”(因为它们基于输入值构造新的输出值),而类型构造函数非常相似,只是不是在值级别,而是在类型级别
例如,Promise
类型构造函数接受一个参数,比如说number
,并由此构造一个新类型,即“NumberPromise”
因此,带参数的类型构造函数在类型级别上有用的原因与带参数的函数在值级别上有用的原因相同:它们允许您从现有内容中构造新内容
为什么参数多态性特别有用?即类型参数完全未知的多态性
记住多态性通常意味着什么:一段代码能够用不同的类型做事情
最著名的多态性形式是即席多态性,其中代码对每种类型执行不同的操作,并且必须对它要处理的每种类型都有一个特定的、单独的实现。ad-hoc多态性最广泛使用的实现是面向对象的虚拟方法调度,其中每个类都有自己独立的方法实现
(实际上,OOP通常使用子类型多态性和即席多态性的组合。此外,它还支持差异代码重用,其中子类型的实现只需要实现它想要实现的不同功能,但可以重用超类型的实现,例如通过继承或原型委派。)
在参数多态性(OTOH)中,只有一个操作适用于所有类型。典型的初学者示例是一个返回单链表长度的函数。它实际上不需要知道元素的类型,因此它可以在元素类型中参数化,如下所示:
函数长度(列表:列表){
return list.rest==未定义?0:1+长度(list.rest);
}
此函数不处理列表中的元素,因此它可以是元素类型上的泛型
另一个例子是标识函数:
函数id(it:T){
归还它;
}
这些函数都是完全参数化的,也就是说,它们适用于您输入的任何类型参数。事实上,他们甚至一点也不在乎类型
但是,有些函数需要了解有关类型的一些信息。例如,列表的排序
函数需要知道元素是可比较的。我们需要在类型参数周围设置某些“边界”,这称为有界多态性:
接口{
常量枚举比较{
LessThan=-1,
相同的
大于
}
比较(其他:T):比较
}
函数排序(列表:列表){
//整理一下
}
关于使用并集和交集类型对这些类型建模的问题,这里的基本区别是,对于参数多态性,类型是用户提供的参数。例如,如果您想通过使用所有可能的元素类型的并集来建模泛型集合类,那么在编写集合之前,您必须事先了解地球上任何人可能编写的所有可能的元素类型!这显然是不可能的。您永远无法列出可以放入列表、映射或数组中的所有可能类型
或者,想想函数类型:如果函数只与特定的穷举联合一起工作,那么它将是非常受限的