本篇内容介绍了“TypeScript泛型如何使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
这里针对一种情况,也是非常常见的一种情况:那就是
function identity(arg: number): number { return arg; }
就是我接收一个number类型的参数,同时也返回一个number,那如果现在我想要接收一个string类型,同时也返回一个string,那么我就要再写一个函数像这样:
function identity2(arg: string): string{ return arg; }
那如果我现在想要void类型…????????????
可能大家会想,那全部都变成any不就行了?像下面这样
function identity(arg: any): any { return arg; }
使用any类型会导致这个函数可以接收任何类型的arg参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的。 如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。
那这样不就与我们一开始的设想不一致了吗?我传入Number,返回string,也不会报错呀!????
因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了类型变量,它是一种特殊的变量,只用于表示类型而不是值。
function identity<T>(arg: T): T { return arg; }
我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。
????‍????我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。 不同于使用any,它不会丢失信息,像第一个例子那像保持准确性,传入数值类型并返回数值类型。
第一种是,传入所有的参数,包含类型参数
第二种方法更普遍。利用了类型推论 – 即编译器会根据传入的参数自动地帮助我们确定T的类型
function identity<T>(arg: T): T { return arg; } let output = identity<string>("myString"); let output2 = identity("myString2"); console.log(output); console.log(output2);
注意我们没必要使用尖括号(<>)来明确地传入类型;编译器可以查看myString的值,然后把T设置为它的类型。 类型推论帮助我们保持代码精简和高可读性。如果编译器不能够自动地推断出类型的话,只能像上面那样明确的传入T的类型,在一些复杂的情况下,这是可能出现的。
我们研究一下函数本身的类型,以及如何创建泛型接口。
来看看泛型类型不同的展现方式:
function identity<T>(arg: T): T { return arg; } let myFunction: <T>(arg:T) => T = identity;
我们也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以。
function identity<T>(arg: T): T { return arg; } let myFunction: <T>(arg:T) => T = identity; 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;
我等这个泛型类等了好久好久????????????
泛型类看上去与泛型接口差不多。 泛型类使用(<>)括起泛型类型,跟在类名后面。
// 泛型类 class GenericNumber<T> { zeroValue: T | undefined; add: ((x: T, y: T) => T) | undefined; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; function myAdd(x:number, y:number) { return x + y; }; myGenericNumber.add = function(x, y) { return x + y; }; console.log(myGenericNumber.add(1,2));
换string玩玩
// 泛型类 class GenericNumber<T> { zeroValue: T | undefined; add: ((x: T, y: T) => T) | undefined; } let stringNumeric = new GenericNumber<string>(); stringNumeric.zeroValue = "hi,"; stringNumeric.add = function(x, y) { return x + y; }; console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));
也不是全能的
与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。
注意点❗❗❗❗❗❗类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
到底有没有长度啊,救命
当我们使用泛型的时候,有这种情况:
我想要打印出传过来的参数的长度为多少
function loggingIdentity<T>(arg: T): T { console.log(arg.length); // Error: T doesn't have .length return arg; }
这里会扯到一个问题,首先,你传过来的这个玩意儿,它本身有长度吗??
首先,什么样的类型会有长度,毫无疑问,数组嘛
那我如果传入的不是数组,那就铁定报错,就像上面那样,正确的写法大家也都懂:
function loggingIdentity<T>(arg: T[]): T[] { console.log(arg.length); // Array has a .length, so no more error return arg; }
相比于操作any所有类型,我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。
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; }
现在传入一个数字试试
传入数组:
我们需要传入符合约束类型的值,必须包含必须的属性:
在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。
跟在Java中的很像——工厂模式,很是高级
function create<T>(c: {new(): T; }): T { return new c(); }
应用场景:传入这个类,自动创建该类并且返回相应的属性。
class BeeKeeper { hasMask: boolean = false; } class ZooKeeper { nametag:string = "ZooKeeper.nametag"; } class Animal { numLegs: number = 100; } class Bee extends Animal { keeper: BeeKeeper = new BeeKeeper(); } class Lion extends Animal { keeper: ZooKeeper = new ZooKeeper(); } function createInstance<A extends Animal>(c: new () => A): A { return new c(); } console.log(createInstance(Lion).keeper.nametag); console.log(createInstance(Bee).keeper.hasMask);
“TypeScript泛型如何使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。