关于对TypeScript泛型参数的默认值理解


Posted in Javascript onJuly 15, 2022

泛型简介

软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C# 和 Java 这样的语言中,可以使用 泛型 来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

举个?

举个最简单的例子来理解泛型?

function getVal(val: string): string {
  return val
}

上述代码很简单,约束 getVal 这个函数入参为 string 类型,约束它的返回值和它的入参一样,也是 string 类型。

关于对TypeScript泛型参数的默认值理解

如上所示,我们传入数值 1 会报错。传入正确类型的参数后,通过上述图像,可以看出 result2 可以调用字符串相关的属性和方法,这是因为 IDE 已经预先推断出了 result2 的类型。

上面的例子是 TypeScript 最基本的应用。此时,我们不妨做一个思考??,getVal 函数就只能接收 string 入参吗?我如果想要实现传入任意类型的值,函数的返回值就是该任意类型怎么实现?

举个??

完成上述提出的疑问可以使用泛型,代码如下?

function getVal<T>(val: T): T {
  return val
}

添加一点测试代码:

关于对TypeScript泛型参数的默认值理解

这一次我们可以传入任何类型的值都不会报错,并且都能够享受 IDE 预推断带来智能提示,这就是 TypeScript 的核心魅力——类型推断和类型约束。

我对于泛型的理解就是:

关于对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 类型数据。

关于对TypeScript泛型参数的默认值理解

  • function create<T extends HTMLElement, U extends HTMLElement>(element: T, children: U[]): Container<T, U[]> 声明一个 create 函数,接收被同样约束为 HTMLElement 类型的 elementchildren 参数。

好了,现在我们来一些测试函数来验证一下以上重载函数的类型推断:

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泛型参数的默认值理解

根据图例,可以看出根据不同的入参个数及入参类型,所推断的函数返回值是跟上面的重载声明一一对应的,这就是 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
  }
}

没错,通过给泛型参数设置默认值,我们只需要写一个普通函数就行了,先看下代码执行效果:

关于对TypeScript泛型参数的默认值理解

我们给 T 设置了一个默认类型 HTMLDivElement 。在解析 create() 语句时,由于没有入参,T 的类型被赋为 HTMLDivElement,而 U = T[],所以 U 的类型是 HTMLDivElement[] ,因此最后的返回值类型推断为 Container<HTMLDivElement, HTMLDivElement[]> 。后续的 r2r3 都是同理。

这里的核心理解要点就是:这里的 T extends HTMLElement = HTMLDivElement, U = T[] 是默认值,只有没传参的时候会生效,如果传参了会被具体的入参类型所替换。

以上便是我对于 TypeScript 中泛型参数默认值的一些粗浅理解,欢迎讨论指正??。

参考

TypeScript 2.3——泛型参数默认值

到此这篇关于对TypeScript泛型参数的默认值理解的文章就介绍到这了,更多相关TS泛型参数默认值内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
获取JavaScript用户自定义类的类名称的代码
Mar 08 Javascript
按下Enter焦点移至下一个控件的实现js代码
Dec 11 Javascript
浅析javascript 定时器
Dec 23 Javascript
JavaScript创建一个object对象并操作对象属性的用法
Mar 23 Javascript
jQuery Mobile框架中的表单组件基础使用教程
May 17 Javascript
JS提示:Uncaught SyntaxError: Unexpected token ILLEGAL错误的解决方法
Aug 19 Javascript
AngularJs ng-route路由详解及实例代码
Sep 14 Javascript
JQuery 动态生成Table表格实例代码
Dec 02 Javascript
jquery实现数字输入框
Feb 22 Javascript
用JavaScript做简易的购物车的代码示例
Oct 20 Javascript
vue+springboot实现项目的CORS跨域请求
Sep 05 Javascript
VueCli生产环境打包部署跨域失败的解决
Nov 13 Javascript
vue递归实现树形组件
Jul 15 #Vue.js
VUE递归树形实现多级列表
Jul 15 #Vue.js
javascript进阶篇深拷贝实现的四种方式
Jul 07 #Javascript
js面向对象编程OOP及函数式编程FP区别
Jul 07 #Javascript
类和原型的设计模式之复制与委托差异
JS高级程序设计之class继承重点详解
Jul 07 #Javascript
JS class语法糖的深入剖析
Jul 07 #Javascript
You might like
一个php作的文本留言本的例子(二)
2006/10/09 PHP
浅析php数据类型转换
2014/01/09 PHP
Zend Framework 2.0事件管理器(The EventManager)入门教程
2014/08/11 PHP
几个实用的PHP内置函数使用指南
2014/11/27 PHP
PHP准确取得服务器IP地址的方法
2015/06/02 PHP
php操作redis缓存方法分享
2015/06/03 PHP
php判断文件上传图片格式的实例详解
2017/09/30 PHP
laravel实现前后台路由分离的方法
2019/10/13 PHP
jquery简单体验
2007/01/10 Javascript
chrome浏览器不支持onmouseleave事件的解决技巧
2013/05/31 Javascript
js动态给table添加/删除tr的方法
2013/08/02 Javascript
extjs中form与grid交互数据(record)的方法
2013/08/29 Javascript
jQuery实现点击文本框弹出热门标签的提示效果
2013/11/17 Javascript
input链接页面、打开新网页等等的具体实现
2013/12/30 Javascript
Jquery 获取指定标签的对象及属性的设置与移除
2014/05/29 Javascript
WordPress中鼠标悬停显示和隐藏评论及引用按钮的实现
2016/01/12 Javascript
js获取Html元素的实际宽度高度的方法
2016/05/19 Javascript
解决vue打包项目后刷新404的问题
2018/03/06 Javascript
vuejs中监听窗口关闭和窗口刷新事件的方法
2018/09/21 Javascript
Angular之jwt令牌身份验证的实现
2020/02/14 Javascript
对vue生命周期的深入理解
2020/12/03 Vue.js
[01:48:04]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Elephant BO3 第一场 2月7日
2021/03/11 DOTA
python设计tcp数据包协议类的例子
2019/07/23 Python
python 读取数据库并绘图的实例
2019/12/03 Python
PyTorch笔记之scatter()函数的使用
2020/02/12 Python
利用css3如何设置没有上下边的列表间隔线
2017/07/03 HTML / CSS
详解background属性的8个属性值(面试题)
2020/11/02 HTML / CSS
HTML5的结构和语义(5):交互
2008/10/17 HTML / CSS
Evisu官方网站:日本牛仔品牌,时尚街头设计风格
2016/12/30 全球购物
奥地利领先的在线药房:SHOP APOTHEKE
2019/10/07 全球购物
伦敦新晋轻奢耳饰潮牌:Tada & Toy
2020/05/25 全球购物
TCP/IP模型的分界线
2012/12/01 面试题
酒店办公室主任岗位职责
2015/04/01 职场文书
2019年消防宣传标语集锦
2019/11/21 职场文书
新手入门Jvm-- JVM对象创建与内存分配机制
2021/06/18 Java/Android
Oracle中DBLink的详细介绍
2022/04/29 Oracle