在 TypeScript 中我们会使用泛【版权所有】唐霜 www.tangshuang.net【原创内容,转载请注明出处】型来对函数的相关类型进行约束。这里的函数转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net,同时包含 class 的构造函数,因此【版权所有,侵权必究】【本文受版权保护】,一个类的声明部分,也可以使用泛型。那么著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。,究竟什么是泛型?如果通俗的理解泛型呢?
著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。【原创不易,请尊重版权】什么是泛型【访问 www.tangshuang.net 获取更多精彩内容】
【作者:唐霜】【作者:唐霜】转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。泛型(Generics)是指在定义函数、【本文受版权保护】原创内容,盗版必究。接口或类的时候,不预先指定具体的类型,而【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。在使用的时候再指定类型的一种特性。
【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】原创内容,盗版必究。原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net
通俗的解释,泛型是类型系统中的“参数”,【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net主要作用是为了类型的重用。从上面定义可以【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。看出,它只会用在函数、接口和类中。它和 本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。js 程序中的函数参数是两个层面的事物(本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。虽然意义是相同的),因为 typescr【转载请注明来源】【未经授权禁止转载】ipt 是静态类型系统,是在 js 进行原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net编译时进行类型检查的系统,因此,泛型这种【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。参数,实际上是在编译过程中的运行时使用。未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。之所以称它为“参数”,是因为它具备和函数本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。参数一模一样的特性。
【本文首发于唐霜的博客】【版权所有,侵权必究】原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.netfunction increse(param) {
// ...
}
而类型系统中,我们如此使用泛型:原创内容,盗版必究。
原创内容,盗版必究。【未经授权禁止转载】【未经授权禁止转载】【未经授权禁止转载】function increase<T>(param: T): T {
//...
}
当 param 为一个类型时,T 被赋值未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net为这个类型,在返回值中,T 即为该类型从【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】而进行类型检查。
本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】编译系统【访问 www.tangshuang.net 获取更多精彩内容】
【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。要知道 typescript 本身的类型【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】系统也需要编程,只不过它的编程方式很奇怪转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】,你需要在它的程序代码中穿插 js 代码【原创内容,转载请注明出处】【作者:唐霜】(在 ts 代码中穿插 js 代码这个说【本文受版权保护】著作权归作者所有,禁止商业用途转载。法很怪,因为我们直观的感觉是在 js 代【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。码中夹杂了 ts 代码)。
【转载请注明来源】【原创内容,转载请注明出处】【本文首发于唐霜的博客】原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。编程中,最重要的一种形式就是函数。在 t【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。ypescript 的类型编程中,你看到【未经授权禁止转载】【关注微信公众号:wwwtangshuangnet】函数了吗?没有。这是因为,有泛型的地方就【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】有函数,只是函数的形式被 js 代码给割【版权所有】唐霜 www.tangshuang.net【本文受版权保护】裂了。typescript 需要进行编译本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net后得到最终产物。编译过程中要做两件事,一【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。是在内存中运行类型编程的代码,从而形成类【未经授权禁止转载】原创内容,盗版必究。型检查体系,也就是说,我们能够对 js 原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】代码进行类型检查,首先是 typescr【作者:唐霜】本文版权归作者所有,未经授权不得转载。ipt 编译器运行 ts 编程代码后得到著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】了一个运行时的检查系统,运行这个系统,从转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。而对穿插在其中的 js 代码进行类型断言【转载请注明来源】【关注微信公众号:wwwtangshuangnet】;二是输出 js,输出过程中,编译系统已【版权所有,侵权必究】【本文受版权保护】经运行完了类型编程的代码,就像 php 【作者:唐霜】【原创内容,转载请注明出处】代码中 echo js 代码一样,php【作者:唐霜】著作权归作者所有,禁止商业用途转载。 代码已经运行了,显示出来的是 js 代【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net码。
【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net【本文受版权保护】从这个角度看 typescript,你或【原创内容,转载请注明出处】原创内容,盗版必究。许更能理解为什么说它是 JavaScri【作者:唐霜】【本文首发于唐霜的博客】pt 的超集,为什么它的编译结果是 js未经授权,禁止复制转载。【未经授权禁止转载】(为什么不可以将 ts 编译为其他语言呢【关注微信公众号:wwwtangshuangnet】?)。【关注微信公众号:wwwtangshuangnet】
【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】通俗的理解泛型本文作者:唐霜,转载请注明出处。
【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】既然我们理解了 ts 编译系统的逻辑,那本文作者:唐霜,转载请注明出处。【未经授权禁止转载】么我们就可以把类型的编程和 js 本身的【原创不易,请尊重版权】【本文受版权保护】业务编程在情感上区分开。我们所讲的“泛型本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】”,只存在于类型编程的部分,这部分代码是【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】 ts 的编译运行时代码。
【本文首发于唐霜的博客】【原创不易,请尊重版权】【作者:唐霜】著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】我们来看下一个简单的例子:本文版权归作者所有,未经授权不得转载。
【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】function increase<T>(param: T): T {
//...
}
这段代码,如果我们把 js 代码区分开,本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。然后用类型描述文本来表示会是怎样?
原创内容,盗版必究。原创内容,盗版必究。转载请注明出处:www.tangshuang.net【未经授权禁止转载】// 声明函数 @type,参数为 T,返回结果为 (T): T
@type = T => (T): T
// 运行函数得到一个类型 F,即类型为 (number): number
@F = @type(number)
// 要求 increase 这个函数符合 F 这种类型,也就是参数为 number,返回值也为 number
@@F
function increase(param) {
// ...
}
@@end
实际上没有 @@F 这种语法,是我编造出【作者:唐霜】【本文首发于唐霜的博客】来的,目的是让你可以从另一个角度去看类型【本文首发于唐霜的博客】未经授权,禁止复制转载。系统。
【关注微信公众号:wwwtangshuangnet】【作者:唐霜】【本文首发于唐霜的博客】【本文首发于唐霜的博客】本文作者:唐霜,转载请注明出处。当我们理解泛型是一种“参数”之后,我们可【原创不易,请尊重版权】【原创内容,转载请注明出处】能会问:类型系统的函数在哪里?对于 js未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net 函数而言,你可以很容易指出函数声明语句本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net和参数,但是 ts 中,这个部分是隐藏起转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】来的。不过,我们可以在一些特定结构中,比【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net较容易看到类型函数的影子:
【转载请注明来源】【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。【转载请注明来源】【版权所有】唐霜 www.tangshuang.net// 声明一个泛型接口,这个写法,像极了声明一个函数,我们用描述语言来形容 @type = T => (T): T interface GenericIdentityFn<T> { (arg: T): T; } // 这个写法,有点像一个闭包函数,在声明函数后,立即运行这个函数,描述语言:@@[T => (T): T](any) function identity<T>(arg: T): T { return arg; } // 使用泛型接口,像极了调用一个函数,我们用描述语言来形容 @type(number) let myIdentity: GenericIdentityFn<number> = identity;
上面这一整段代码,我们用描述文本重写一遍【版权所有,侵权必究】【版权所有】唐霜 www.tangshuang.net:
【版权所有,侵权必究】本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。@GenericIdentityFn = T => (T): T
@@[T => (T): T](any)
function identify(arg) {
return arg
}
@@end
@@GenericIdentityFn(number)
let myIdentity = identity
@@end
我们在类型系统中声明了两个函数,分别是 原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net@GenericIdentityFn 和【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net @some(匿名函数 @[T =>【版权所有】唐霜 www.tangshuang.net【作者:唐霜】; (T): T])。虽然是两个函数,但【原创不易,请尊重版权】【原创内容,转载请注明出处】是实际上,它们的是一模一样的,因为 ty【转载请注明来源】本文作者:唐霜,转载请注明出处。pescript 是结构类型,也就是在类未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】型检查的时候只判断结构上的每个节点类型是【本文受版权保护】【转载请注明来源】否相同,而不是必须保持类型变量本身的指针【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net相同。@GenericIdentityF【关注微信公众号:wwwtangshuangnet】【原创内容,转载请注明出处】n 和 @some 这两个函数分别被调用本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】,用来修饰 identify 和 myI著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。dentify,在调用的时候,接收的参数原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。不同,所以导致最终的类型检查规则是不同的原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】,identify 只要保证参数和返回值未经授权,禁止复制转载。【转载请注明来源】的类型相同,至于具体什么类型,any。而著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。 myIdentify 除了保证参数返回本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。值类型相同外,还要求类型必须是 numb【本文首发于唐霜的博客】【本文首发于唐霜的博客】er。
【原创内容,转载请注明出处】【版权所有,侵权必究】【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。【本文受版权保护】泛型类【版权所有】唐霜 www.tangshuang.net
【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。【原创不易,请尊重版权】除了泛型接口,class 类也可以泛型化【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net,即“泛型类”,借助泛型类,我们来探究一【访问 www.tangshuang.net 获取更多精彩内容】本文版权归作者所有,未经授权不得转载。下泛型的声明和使用的步骤。
【关注微信公众号:wwwtangshuangnet】【访问 www.tangshuang.net 获取更多精彩内容】【未经授权禁止转载】class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
前文泛型接口因为只是为了约束函数的类型,【本文受版权保护】【本文首发于唐霜的博客】所以写的很像函数,实际上,我们可以用描述【访问 www.tangshuang.net 获取更多精彩内容】【原创内容,转载请注明出处】语言重新描述一个泛型接口和泛型类。上面的未经授权,禁止复制转载。【转载请注明来源】红色部分,我们用描述语言来描述:
【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。【本文受版权保护】@GenericNumber = T => class {
zeroValue: T;
add: (x: T, y: T) => T;
}
@GenericNumber 这个函数,【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net以 T 为参数,返回一个 class,在【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】函数体内多次用到了参数 T。
本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net【本文受版权保护】【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net@GenericIdentityFn = T => interface {
(arg: T): T;
}
我们重新描述了前面的 interface转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net GenericIdentityFn,这著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。样我们就可以在接口中增加其他的方法。
未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。可以注意到,即使 typescript 本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】内置的基础类型,例如 Array,被声明原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。为泛型接口、泛型类之后,这些接口和类在使著作权归作者所有,禁止商业用途转载。【转载请注明来源】用时必须通过<>传入参数,本【原创内容,转载请注明出处】【本文受版权保护】质上,因为它们都是函数,只是返回值不同。
转载请注明出处:www.tangshuang.net【本文受版权保护】本文版权归作者所有,未经授权不得转载。其他泛型使用的通俗解释著作权归作者所有,禁止商业用途转载。
【本文首发于唐霜的博客】【原创内容,转载请注明出处】【本文受版权保护】著作权归作者所有,禁止商业用途转载。接下来我们要再描述一个复杂的类型:【版权所有,侵权必究】
【未经授权禁止转载】原创内容,盗版必究。【转载请注明来源】【原创不易,请尊重版权】【版权所有】唐霜 www.tangshuang.netclass Animal {
numLegs: number;
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
我们姑且不去看 new() 的部分,我们本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】看尖括号中的 extends 语法,这里本文作者:唐霜,转载请注明出处。【本文受版权保护】应该怎么理解呢?实际上,我们面对的问题是【版权所有,侵权必究】【原创内容,转载请注明出处】,在编译时,<A extends Animal【未经授权禁止转载】> 尖括号中的内容是什么时候运行的本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。,是之前,还是之间?
原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。// 到底是
@type = (A extends Animal) => (new() => A): A
@type(T)
// 还是
@type = A => (new() => A): A
@type(T extends Animal)
因为 typescript 是静态类型系【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net统,Animal 是不变的类,因此,可以【作者:唐霜】【原创内容,转载请注明出处】推测其实在类的创建之前,尖括号的内容已经【版权所有,侵权必究】未经授权,禁止复制转载。被运行了。
未经授权,禁止复制转载。【未经授权禁止转载】转载请注明出处:www.tangshuang.net@type = (A extends Animal) => (new() => A): A
也就是说,要使用 @type(T) 产生【版权所有,侵权必究】原创内容,盗版必究。类型,首先 T 要满足 Animal 的本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】结构,然后才能得到需要的类型,如果 T 转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net已经不满足 Animal 类的结构了,那【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。么编译器会直接报错,而这个报错,不是类型著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。检查阶段,而是在类型系统的创建阶段,也就原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net是 ts 代码的运行阶段。这种情况被称为【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net“泛型约束”。
转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net【本文受版权保护】未经授权,禁止复制转载。另外,类似 <A,B> 这样【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net的语法其实和函数参数一致。
著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】原创内容,盗版必究。@type = (A, B) => (A|B): SomeType
我们再来看 ts 内置的基础类型:Arr原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】ay<number>
【未经授权禁止转载】本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】【关注微信公众号:wwwtangshuangnet】【本文受版权保护】@Array = any => any[]
结语【本文受版权保护】
【作者:唐霜】转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。Typescript 中的泛型,实际上就著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】是类型的生成函数的参数。本文的内容全部为【原创内容,转载请注明出处】原创内容,盗版必究。凭空想象,仅适用于对 ts 进行理解时的【转载请注明来源】【作者:唐霜】思路开拓,不适用于真实编程,特此声明。
本文作者:唐霜,转载请注明出处。【未经授权禁止转载】本文作者:唐霜,转载请注明出处。【转载请注明来源】本文版权归作者所有,未经授权不得转载。2019-12-04 5118 TypeScript, 类型检查


