当前位置:网站首页>LayaBox---TypeScript---泛型
LayaBox---TypeScript---泛型
2022-07-30 17:38:00 【格拉格拉】
目录
1.泛型之hello world
不用泛型的话,这个函数可能是下面这样:
function identity(arg: number): number
{
return arg;
}
或者,使用any类型来定义函数:
function identity(arg: any): any
{
return arg;
}
使用any类型会导致这个函数可以接收任何类型的arg参数,这样就丢失了一些信息:
传入的类型与返回的类型应该是相同的。如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。
因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,
它是一种特殊的变量,只用于表示类型而不是值。
function identity<T>(arg: T): T
{
return arg;
}我们定义了泛型函数后,可以用两种方法使用。
1.传入所有的参数,包含类型参数:
let output = identity<string>("myString"); // type of output will be 'string'
2.利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型:
let output = identity("myString"); // type of output will be 'string'2.泛型变量
如果我们想同时打印出arg的长度。 我们很可能会这样做:
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有 .length属性的。
//-----------------------------------------------------------------------------
现在假设我们想操作T类型的数组而不直接是T。由于我们操作的是数组,所以.length属性是应该存在的。
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
我们也可以这样实现上面的例子
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}3.泛型类型
泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样:
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <T>(arg: T) => T = identity;
//也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以。
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <U>(arg: U) => U = identity;
//还可以使用带有调用签名的对象字面量来定义泛型函数:
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: {<T>(arg: T): T} = identity;这引导我们去写第一个泛型接口了。拿上面的例子里的对象字面量作为一个接口:
interface GenericIdentityFn
{
<T>(arg: T): T;
}
function identity<T>(arg: T): T
{
return arg;
}
let myIdentity: GenericIdentityFn = identity;
一个相似的例子:
如果我们想把泛型参数当作整个接口的一个参数,这样就能清楚的知道使用的具体是哪个泛型类型(比如: Dictionary<string>而不只是Dictionary)。 这样接口里的其它成员也能知道这个参数的类型了。
interface GenericIdentityFn<T>
{
(arg: T): T;
}
function identity<T>(arg: T): T
{
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;️注意,我们的示例做了少许改动。 不再描述泛型函数,而是把非泛型函数签名作为泛型类型一部分。 当我们使用 GenericIdentityFn的时候,还得传入一个类型参数来指定泛型类型(这里是:number),锁定了之后代码里使用的类型。
4.泛型类
除了泛型接口,我们还可以创建泛型类。 ️注意无法创建 泛型枚举 和 泛型命名空间
泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
没有什么去限制它只能使用number类型。 也可以使用字符串或其它更复杂的类型。
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));️注意:类有两部分:静态部分和实例部分。
泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
5.泛型约束
你应该会记得在 loggingIdentity例子中,我们想访问arg的length属性,但是编译器并不能证明每种类型都有length属性,所以就报错了。
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}为此,我们定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
loggingIdentity(3); // Error, number doesn't have a .length property
我们需要传入符合约束类型的值,必须包含必须的属性:
loggingIdentity({length: 10, value: 3});
1.在泛型约束中使用类型参数
声明一个类型参数,且它被另一个类型参数所约束。
现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,
因此我们需要在这两个类型之间使用约束。
function getProperty(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.2.在泛型里使用类类型
在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。
function create<T>(c: {new(): T; }): T {
return new c();
}一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance < A extends Animal >(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!边栏推荐
- C陷阱与缺陷 第7章 可移植性缺陷 7.1 应对C语言标准变更
- JMeter笔记3 | JMeter安装和环境说明
- Weka 3.8.6安装与Weka 3.8.6功能介绍
- un7.30:Linux——如何在docker容器中显示MySQL的中文字符?
- 数据预处理:离散特征编码方法
- Redis缓存穿透-热点缓存并发重建-缓存与数据库双写不一致-缓存雪崩
- C陷阱与缺陷 第6章 预处理器 6.1 不能忽视宏定义中的空格
- Express framework connects MySQL and ORM framework
- 论文阅读之《Quasi-Unsupervised Color Constancy 》
- What is industrial radiography equipment?
猜你喜欢

Basic knowledge points in js - BOM

C陷阱与缺陷 第7章 可移植性缺陷 7.5 移位运算符

un7.30:Linux——如何在docker容器中显示MySQL的中文字符?

SQLServer下载与安装

Metaverse Web 3.0 和 DeFi大师班

Promise entry to proficient (1.5w word detailed explanation)

JMeter笔记3 | JMeter安装和环境说明

链表Oj练习题 纯C语言

This year..I sincerely recommend the professional engineer to upgrade to the book!

论文阅读之《Quasi-Unsupervised Color Constancy 》
随机推荐
高级语言垃圾回收思路和如何减少性能影响原理分析
952. 按公因数计算最大组件大小 : 枚举质因数 + 并查集运用题
如何让 JOIN 跑得更快?
KDD 2020 | 深入浅出优势特征蒸馏在淘宝推荐中的应用
JMeter Notes 3 | JMeter Installation and Environment Instructions
C陷阱与缺陷 第6章 预处理器 6.1 不能忽视宏定义中的空格
习题:变量、常量和基本数据类型
测试行业干了5年,从只会点点点到了现在的测试开发,总算是证明了自己
un7.30:linux——如何在docker容器中安装MySQL?
Logback的使用
Promise entry to proficient (1.5w word detailed explanation)
知识蒸馏1:基础原理讲解及yolov5项目实战介绍
数据库系统原理与应用教程(063)—— MySQL 练习题:操作题 39-50(七):SELECT 基本语法联系
Ecplise执行C语言报错:cannot open output file xxx.exe: Permission denied
Mysql brush dirty several scenarios and related parameters
Analysis and Simulation of Short Circuit Fault in Power System Based on MATLAB
论文阅读之《Color Constancy Using CNNs》
KDD‘21推荐系统离散特征表征无embedding table Learning to Embed Categorical Features without Embedding Tables for
[OC学习笔记]属性关键字
mysql刷脏的几种场景以及相关参数