前言

使用 TypeScript 进行开发也已经有段日子了,虽然最开始接触后以为这不就和 Java 一样一样的么,然而越深入了解越发现还真不一样~不过有些概念来说是相通的,比如泛型。 Java 里也有函数重载,但是和 TS 差别还是挺大的,那就通过一个排序功能来了解一下 TS 中的泛型重载吧

TypeScript 的运行环境

1. ts-node

ts-node 是 typescript 的 node.js 解释和执行器,也就是说,它可以像 node 执行 JavaScript 一样执行 typescript 代码。

使用方式也很简单,在项目中安装 typescript 和 ts-node 的依赖后使用 ts-node 命令执行 ts 文件即可。

1.在命令行安装依赖

npm install typescript ts-node

2.使用 ts-node 运行 ts 文件(这里使用 npx 来执行 ts-node,因为 ts-node 是在本地项目中安装的,如果直接使用的话会报命令找不到的错误,当然如果在全局安装了 ts-node npm 包就直接可以使用 ts-node 来运行,如果只是本地安装了,那么需要加上 npx,这是会到 node_modules 文件夹中找到 ts-node 包来进行执行。)

全局安装了: ts-node: ts-node xxx.ts
本地项目安装了 ts-node: npx ts-node xxx.ts

补充: ts-node 也可以直接在命令行中编写和执行 ts 代码,像 python 那样,

如下图:

ts-node.png

2. tsc

tsc 顾名思义就是 typescript 的编译器名称,在安装完 typescript 后,即可以使用 tsc 命令执行 ts 文件,当然不同于 ts-node 能够直接运行 ts 文件,tsc 只是将 ts 文件编译后输出成 js 文件,然后可以再通过 node 来执行生成的 js 文件。

tsc 有许多的配置项,当运行 tsc --init 时可以在项目中生成 tsconfig.json 文件,这个文件里面包含了许多的配置,包括配置编译后的文件输出路径,编译后的文件用哪种模块规范以及兼容 es6 语法等等选项。

//1.安装 typescript
npm install typescript

//2.使用 tsc 生成 tsconfig.json 文件
npx tsc --init

//3.使用 tsc 编译 ts 文件
npx tsc xxx.ts

TypeScript 中的函数重载

TS 中的函数重载并不像其它语言中的函数重载一样,和其它语言如 Java 比起来,更像是一种伪重载,它不能像 Java 中重载那样实现同样的函数名,但是参数个数不一样,而是更多的为类型推断服务。

简单的排序算法

首先,使用 TS 来实现一个快速排序函数:

1. 快速排序

function quickSort<T>(arr: Array<T>): T[] {
    if (arr.length < 2) return arr

    const left: Array<T> = []
    const right: Array<T> = []

    const mid = arr.splice(Math.floor(arr.length / 2), 1)[0]
    for (let item of arr) {
        if (item < mid) {
            left.push(item)
        } else {
            right.push(item)
        }
    }
    return quickSort(left).concat(mid, quickSort(right))
}

上面这段代码是使用泛型实现的快速排序函数,快速排序比冒泡排序的性能要好很多,基本思想就是分治(divide and conquer),简单来说就是先选一个元素作为中间数,然后分成两部分,小于这个元素的部分,和大于这个元素部分,接着再使用递归分别进行处理这两部分,将排序任务分解到最小,然后再合并。

上面代码中的快速排序方式,如果传递的是英文数组那就没问题,但是如果传递的是中文数组,那就不能正常排序了,所以中文数组需要单独进行处理,使用下面的函数:

2. 中文排序

// 通过正则表达式,判断是否是中文数组
function isChinese<T>(arr: Array<T>): boolean {
    const pattern = /[\u4e00-\u9fa5] /g;
    return arr.some((item: any) => {
        return pattern.test(item)
    })
}

// 中文排序
function chineseSort<T>(arr: Array<T>): T[] {
    return arr.sort((first, second) => {
        return (first as any).localeCompare(second, 'zh-CN')
    })
}

如果是中文数组,那么使用数组内置的 sort 函数进行排序。

接下来,如果需要将英文数组中的每一项进行排序,则还需要单独的函数进行处理:

3. 字符串自排序

// 英文自排序
function strSelfSort(str: string): string {
    const strArr = str.split('')
    return quickSort(strArr).join('')
}

实现英文字符串自排序就是先将字符串进行 split 分割成字符数组,然后传递到之前写的快速排序函数中,得到结果后再通过 join 函数拼接成字符串返回。

那么,接下来将上面的几种排序功能整合成一个单独的通用函数:

4. 通过泛型整合几种排序

// 通用的排序函数
function sort<T>(data: T): T[] | string {
    if (typeof data === "string") {
        return strSelfSort(data)
    }
    if (data instanceof Array) {
        if (isChinese(data)) {
            return chineseSort(data)
        }
        const newArr = data.map((item) => {
            return typeof item === "string" ? strSelfSort(item) : item
        })
        return quickSort(newArr)
    }
    throw new Error(`data must be string or array. ${data}`)
}

通过上面的通用排序函数可以看出,在函数内部通过排序传递的数据类型,如果是 string 则调用自排序,接着如果是数组的话,再判断是否是中文数组,如果是,则调用中文数组排序函数进行排序,不是的话就认定为是英文数组,英文数组首先使用 map 函数遍历,判断数组中如果存在 string 类型就先调用字符串自排序函数进行排序,否则就原样返回,最后再通过快速排序函数进行排序,这样就完成了英文数组既每一项都排序了,整体数组也进行了排序。

虽然上面的排序函数功能已经比较完善了,但是有一点不太好的地方就是这个函数返回了一个联合类型 T[] | string,这样就会导致通过这个函数排序的结果不能确切的推断出具体的类型,而只能是个联合类型,那么我们也只能使用这个联合类型里共有的方法提示,

如下图:

image.png

image.png

这里简单的调用了一下写好的排序函数,返回的结果类型竟然是:string | string[][] 的联合类型,这样的返回结果对于开发后续功能来说很不友好,那么接下来,就使用 TS 中的函数重载来完善一下上面的排序函数:

5. 使用函数重载完善排序功能

// 使用函数重载重构排序函数
function sort(data: string): string
function sort<T>(data: T): T
function sort(data: any): any {
    if (typeof data === "string") {
        return strSelfSort(data)
    }
    if (data instanceof Array) {
        if (isChinese(data)) {
            return chineseSort(data)
        }
        const newArr = data.map((item) => {
            return typeof item === "string" ? strSelfSort(item) : item
        })
        return quickSort(newArr)
    }
    throw new Error(`data must be string or array. ${data}`)
}

关于 TS 的函数重载,就是只有一个实现的函数,其余都是函数签名,而且必须放在实现函数的上面,在调用这个函数的时候,只会显示上面的函数签名函数,而不会展示具体实现的函数,但是实际执行的却是那个实现函数,在这种情况下,通过使用函数重载写个两个不同参数和返回值的函数签名提供给调用者使用,而在具体实现函数中去兼容处理,这样做的好处就是调用者得到的返回值类型可以是某个具体的类型了,而不再是个联合类型,更有益于后面的开发。

总结

通过使用 TS 的函数重载解决了当一个函数返回一个联合类型时,类型推断不确定的问题,在某些会返回联合类型的场景下可以尝试使用,方便后续的类型推断操作,所以说,TS 的一切真的都是为类型而服务的,怎么写好 TS 代码其实就是在更好的完善类型推断,类型系统的过程,只有更好更准确的类型推断,才能发挥 TS 的作用,让编译器在开发过程中智能的告诉开发者有哪些属性和方法可以调用,并且在调用了错误的属性和方法后可以及时提醒开发者。

到此这篇关于TypeScript 泛型重载函数的使用方式的文章就介绍到这了,更多相关TypeScript 泛型重载函数 内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

TypeScript 泛型重载函数的使用方式的更多相关文章

  1. ios – 如何在Swift中使用没有类型参数的泛型类?

    解决方法Swift还不像Java那样支持wildcard-stylegenerics(即Animal

  2. ios – 如何在Swift中向下转换/转换结构的泛型类型

    我是否必须将这些存储为Any的数组,然后每次都将它们转换为或者我只是误解某些(或两者)?

  3. ios – 在XCTestCase子类中使用泛型有效吗?

    我有一个XCTestCase子类,看起来像这样.为了简洁起见,我已经删除了setup()和tearDown方法:它的子类看起来像这样:在理论上,这应该按预期工作–编译器不会抱怨任何事情.但是只是当我运行测试用例时,setup()方法甚至没有被调用.但是,它表明当testName()方法应该失败时,测试已经过去了.使用泛型是一个问题吗?我可以很容易地想到很多非通用的方法,但是我很想写这样的测试用例.这是XCTest在Objective-C和Swift之间的互操作性?Ergo您的通用XCTestCase子类不

  4. 泛型 – Xcode构建错误时,我添加枚举到泛型类?

    为什么在将泛型类添加到枚举时会收到错误:错误:但是当我这样做时,我没有收到错误:或这个:解决方法您不能将任何类型嵌套在通用的类型中,反之亦然.换句话说,你不能像类,结构和枚举这样做的事情:和乃至苹果人explained的限制原因:It’sanimplementationlimitation.We’llremovetherestrictiononceourcompilerandruntimearea

  5. ios – 如何通过Swift中的泛型类型构造一个属性?

    我在swift中创建了一个泛型类,我想使用“AdaptorType”类型初始化一个适配器,但是我收到一个编译错误我也尝试在init()中初始化它,但是同样的问题在于使用通用类型AdaptorType初始化适配器属性的正确方法是什么?

  6. ios – Equatable实现似乎不适用于泛型

    我仍然在与Swift仿制药作斗争.今天我发现我的Equatable协议实现不起作用,如果它是从泛型类调用的.我的模特课:类,使用泛型类型:它的子类:当我调用TrackingCache实例的removeEntities方法时,我总是在输出中得到相等的:false,即使id是相同的.但是,如果我直接将方法移动到TrackingCache类,它似乎工作正常!

  7. 泛型 – MonoTouch和支持变体通用接口

    如果是这样,MonoTouch中针对这种情况的推荐解决方法是什么?解决方法这实际上取决于编译器而不是Mono版本.IOW有些东西可能适用于Mono2.10而不适用于MonoTouch6.x.当前版本的MonoTouch附带了smcs编译器和基于2.1的配置文件.较新的功能,如协方差,需要一个完整的4.0编译器和运行时.未来版本的MonoTouch将提供4.0/4.5运行时和编译器.

  8. 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 24 Generics

    它可以避免重复的代码,用一种清晰和抽象的方式来表达代码的意图//泛型是Swift强大特征中的一个,许多Swift标准库都是通过泛型代码构建出来的。{forinenumerate{//遍历索引固定字符串的下标ifvalue==valuetoFind{returnindex}}returnnil}letstrings=["cat","dog","llama","parakeet"]ifletfoundindex=findStringIndex{p

  9. Swift语法基础:7 - Swift的Generics

    在前面,我们知道了Swift中的Protocol和Extensions,现在我们来看看另一个东西:Generics(泛型)1.泛型的声明以及简单使用PS:所谓的泛型其实就是一个比较特殊的数组,它可以存储不同类型的数据,这样子我们在写方法的时候,就不需要再写多一个相同功能而类型不同的方法了.2.枚举类型中的泛型3.特定需求的泛型PS:如果你需要某个指定样式的泛型,那么就必须得在泛型里加上where这

  10. Swift泛型和泛型函数

    1、泛型函数在函数名后面加,参数类型也被声明为T,T成为占位符,函数在每次调用时传入实际的参数类型才决定T的类型funclog4{println}log4log4log4如果有多个不同类型,可以使用其它大写字母,一般习惯使用U,多个占位符使用逗号,隔开:示例如下:funcisEquals->Bool{}占位符不仅可以替代参数类型,还可以替代返回值类型:funcisEquals->T{}2、泛型约束有些占位符必须遵守某种协议,及T占位符后面添加冒号和协议类型,这种表示方式成为泛型约束,它能够替换T的类型。

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部