如何理解TypeScript泛型参数,要点有什么
Admin 2022-09-08 群英技术资讯 274 次浏览
软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像C# 和 Java 这样的语言中,可以使用 泛型 来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
举个最简单的例子来理解泛型
function getVal(val: string): string {
return val
}
上述代码很简单,约束 getVal
这个函数入参为 string
类型,约束它的返回值和它的入参一样,也是 string
类型。
如上所示,我们传入数值 1
会报错。传入正确类型的参数后,通过上述图像,可以看出 result2
可以调用字符串相关的属性和方法,这是因为 IDE 已经预先推断出了 result2
的类型。
上面的例子是 TypeScript 最基本的应用。此时,我们不妨做一个思考????????,getVal
函数就只能接收 string
入参吗?我如果想要实现传入任意类型的值,函数的返回值就是该任意类型怎么实现?
完成上述提出的疑问可以使用泛型,代码如下
function getVal<T>(val: T): T {
return val
}
添加一点测试代码:
这一次我们可以传入任何类型的值都不会报错,并且都能够享受 IDE 预推断带来智能提示,这就是 TypeScript 的核心魅力——类型推断和类型约束。
我对于泛型的理解就是:
我们程序员在看到 '123'
、true
等变量时,我们一眼就能看出它是什么类型,计算机当然也能够识别出来。TypeScript
引擎通过解析 AST 的方式推断出了 getVal
的入参类型为 string
,将推断出来的类型用一个变量 T
存起来,这样我们可以将 T
灵活的运用在各种地方。总之,我们可以将泛型看成是一个变量或者是一个形参,只不过在 JavaScript 中变量存储的是值,而 TypeScript 中存储的是类型罢了。
我们在上面说到,泛型可以看成是一个形参。在 JavaScript 中形参可以设置一个默认值,那么在 TypeScript 中的泛型参数同样可以设置一个默认值。我们来看一下官方的示例代码
declare function create(): Container<HTMLDivElement, HTMLDivElement[]>;
declare function create<T extends HTMLElement>(element: T): Container<T, T[]>;
declare function create<T extends HTMLElement, U extends HTMLElement>(
element: T,
children: U[]
): Container<T, U[]>;
示例代码中缺少 Container
类型声明,并且函数只有类型声明没有的具体执行代码块,直接复制到编辑器中会报错。这里我们尝试补充一下,如下:
type Container<T, U> = {element: T, children: U}
function create(): Container<HTMLDivElement, HTMLDivElement[]>;
function create<T extends HTMLElement>(element: T): Container<T, T[]>;
function create<T extends HTMLElement, U extends HTMLElement>(element: T, children: U[]): Container<T, U[]>;
function create<T extends HTMLElement, U extends T[]>(element?: T, children?: U): Container<T, U> {
return {
element: element as T,
children: children as U
}
}
以上代码是一个重载函数的声明,函数重载允许一个函数接受不同数量或类型的参数时,作出不同的处理(PS:这里的处理就是会有不同的类型推断和约束)。
我们先一行一行的解析它的重载声明含义
function create(): Container<HTMLDivElement, HTMLDivElement[]>
声明一个 create
函数,无入参,返回值是一个包含 HTMLDivElement
类型的 Container
类型数据。function create<T extends HTMLElement>(element: T): Container<T, T[]>
声明一个 create
函数,接收一个被约束为 HTMLElement
类型的 element
参数(通过下图可以看出,像这些DOM类型可以满足 HTMLElement
类型约束),返回值是一个包含满足 HTMLElement
类型的 Container
类型数据。function create<T extends HTMLElement, U extends HTMLElement>(element: T, children: U[]): Container<T, U[]>
声明一个 create
函数,接收被同样约束为 HTMLElement
类型的 element
和 children
参数。好了,现在我们来一些测试函数来验证一下以上重载函数的类型推断:
const r1 = create() // Container<HTMLDivElement, HTMLDivElement[]>
const r2 = create(document.createElement('dialog')) // Container<HTMLDialogElement, HTMLDialogElement[]>
const children = [document.createElement('div')] // HTMLDivElement[]
const r3 = create(document.createElement('dialog'), children) // Container<HTMLDialogElement, HTMLDivElement[]>
根据图例,可以看出根据不同的入参个数及入参类型,所推断的函数返回值是跟上面的重载声明一一对应的,这就是 TypeScript 中最基础的函数重载的理解。看到这里,相信有很多人会有疑问,一个函数重载写这么多行声明,需要搞这么麻烦,TS……劳资不学了。
由于前面的那么多铺垫,这篇文章的主题部分已经可以一带而过了~
有了泛型参数默认类型,我们可以将上面复杂的重载声明简化为这样
function create<T extends HTMLElement = HTMLDivElement, U = T[]>(element?: T, children?: U): Container<T, U> {
return {
element: element as T,
children: children as U
}
}
没错,通过给泛型参数设置默认值,我们只需要写一个普通函数就行了,先看下代码执行效果:
我们给 T
设置了一个默认类型 HTMLDivElement
。在解析 create()
语句时,由于没有入参,T
的类型被赋为 HTMLDivElement
,而 U = T[]
,所以 U
的类型是 HTMLDivElement[]
,因此最后的返回值类型推断为 Container<HTMLDivElement, HTMLDivElement[]>
。后续的 r2
和 r3
都是同理。
这里的核心理解要点就是:这里的 T extends HTMLElement = HTMLDivElement, U = T[]
是默认值,只有没传参的时候会生效,如果传参了会被具体的入参类型所替换。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
Node中怎么操作文件?下面本篇文章带大家聊聊怎么使用Nodejs读写文件,希望对大家有所帮助!
这篇文章给大家分享的是用jQuery实现消息提醒闪烁的效果。消息提醒闪烁我们在很多网站或是涉及软件上都见过,那么如何自己动手实现这个效果呢?文中的示例代码介绍得很详细,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。
这篇文章主要介绍了Vue实现圆环进度条的示例,帮助大家更好的理解和使用前端框架进行开发,感兴趣的朋友可以了解下
React服务端渲染原理是什么?很多朋友可能听说过React服务端渲染,但是对其原理并不清楚,因此下面小编就给大家介绍一下React服务端渲染原理以及实例,感兴趣的朋友可以参考。
这篇文章给大家分享的是微信小程序中列表信息展开收起的效果的实现。小编觉得挺实用的,因此分享给大家做个参考,文中示例代码介绍的非常详细,感兴趣的朋友接下来一起跟随小编看看吧。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008