TypeScript 泛型重载函数的使用方式

目录
  • 前言
  • TypeScript 的运行环境
    • 1. ts-node
    • 2. tsc
  • TypeScript 中的函数重载
  • 简单的排序算法
    • 1. 快速排序
    • 2. 中文排序
    • 3. 字符串自排序
    • 4. 通过泛型整合几种排序
    • 5. 使用函数重载完善排序功能
  • 总结

前言

使用 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 那样,

如下图:

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,这样就会导致通过这个函数排序的结果不能确切的推断出具体的类型,而只能是个联合类型,那么我们也只能使用这个联合类型里共有的方法提示,

如下图:

这里简单的调用了一下写好的排序函数,返回的结果类型竟然是: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 泛型重载函数 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • TypeScript泛型约束条件示例详解

    目录 什么是泛型 泛型的应用场景 泛型约束(限制条件) 泛型函数调用指定类型 总结 什么是泛型 两个值之间存在的对应关系,就可以用泛型来解决 泛型的应用场景 当一个函数的返回值的类型需要与此函数的参数类型想关联的时候,就需要使用泛型 例如 //约定此函数调用时必须传入一个数组,并返回数组第一项 function arrFn <T> (arr: T[]) :T|undefined { return arr[0] } const n = arrFn([1,2]) //number类型 const

  • TypeScript中的接口和泛型你了解吗

    目录 接口 对象类型 索引类型 函数类型 继承 交叉类型 接口实现 interface和type的区别 字面量赋值 枚举类型 泛型 泛型函数 泛型接口 泛型类 类型约束 总结 接口 使用 interface 关键字来定义数据类型 对象类型 当存在于较长的数据类型约束时,我们可以通过 type 关键字 为类型注解起别名,也可以通过接口来定义 type UserType = { name: string; age?: number }; const user: UserType = { name:

  • typeScript 泛型使用和泛型接口结合

    目录 1.泛型是啥? 2.泛型类型 3.泛型接口 4.泛型类 5.泛型约束 6.泛型参数默认类型 7.泛型条件类型 typeScript 中新增的泛型概念.泛型使用.泛型与接口结合: 在实际应用中可能会遇到求最小值的问题,比如求数组中的最小值. 在 ts 中的就需要写两种方式,一种针对 number,另外一种针对字符串. 这样写不利于代码重用,项目较大时,性能较差,同时工作效率也低,所以在 ts 中引入了泛型概念. function getMin1(arr:number[]):number {

  • 在 TypeScript 中使用泛型的方法

    目录 1. 泛型语法 2. 在函数中使用泛型 (1)分配泛型参数 (2)直接传递类型参数 (3)默认类型参数 (4)类型参数约束 3. 在接口.类和类型中使用泛型 (1)接口和类中的泛型 (2)自定义类型中的泛型 4. 使用泛型创建映射类型 5. 使用泛型创建条件类型 (1)基础条件类型 (2)高级条件类型 6. 小结 前言: 泛型是静态类型语言的基本特征,允许将类型作为参数传递给另一个类型.函数.或者其他结构.TypeScript 支持泛型作为将类型安全引入组件的一种方式.这些组件接受参数和返

  • 前端深入理解Typescript泛型概念

    首先介绍一下泛性的概念 泛型程序设计(generic programming)是程序设计语言的一种风格或范式.泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型. 泛型是指在定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性. 先举一个简单的例子 假设我们定义一个函数,它可以接收一个number类型做为参数,并且返回一个number类型. function genericDemo(data: number):

  • 如何通俗的解释TypeScript 泛型

    概述 在 TypeScript 中我们会使用泛型来对函数的相关类型进行约束.这里的函数,同时包含 class 的构造函数,因此,一个类的声明部分,也可以使用泛型.那么,究竟什么是泛型?如果通俗的理解泛型呢? 什么是泛型 泛型(Generics)是指在定义函数.接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性. 通俗的解释,泛型是类型系统中的"参数",主要作用是为了类型的重用.从上面定义可以看出,它只会用在函数.接口和类中.它和js程序中的函数参数是两个层面的事物

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

    目录 泛型简介 举个 举个 泛型参数的默认值——函数重载 泛型参数的默认值——正文 参考 泛型简介 软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性. 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能. 在像C# 和 Java 这样的语言中,可以使用 泛型 来创建可重用的组件,一个组件可以支持多种类型的数据. 这样用户就可以以自己的数据类型来使用组件. 举个 举个最简单的例子来理解泛型 function getVal(

  • TypeScript泛型参数默认类型和新的strict编译选项

    概述 TypeScript 2.3 增加了对声明泛型参数默认类型的支持,允许为泛型类型中的类型参数指定默认类型. 接下来看看如何通过泛型参数默认将以下react组件从js(和jsX)迁移到 TypeScript (和TSX): class Greeting extends react.Component { render() { return <span>Hello, {this.props.name}!</span>; } } 为组件类创建类型定义 咱们先从为Component类

  • TypeScript 泛型的使用

    目录 1.简单的使用 2.在函数中使用泛型 3.在类中使用泛型 4.在泛型约束中使用类型参数 前言: 在JavaScript中,封装一个API可以具有多种用途,因为其实弱类型语言,但是就因为是弱类型可以最终得到的结果并不是我们想要的. TypeScript的出现正好中解决了这个问题,但是考虑到API的复用时,TypeScript又显得不是这么的灵活.这个时候可以使用any类型来解决不灵活的问题,但是又回到JavaScript中的问题,得到最终的结果可能不是预期的那个样子. 为了解决这种情况,Ty

  • TypeScript 泛型重载函数的使用方式

    目录 前言 TypeScript 的运行环境 1. ts-node 2. tsc TypeScript 中的函数重载 简单的排序算法 1. 快速排序 2. 中文排序 3. 字符串自排序 4. 通过泛型整合几种排序 5. 使用函数重载完善排序功能 总结 前言 使用 TypeScript 进行开发也已经有段日子了,虽然最开始接触后以为这不就和 Java 一样一样的么,然而越深入了解越发现还真不一样~不过有些概念来说是相通的,比如泛型. Java 里也有函数重载,但是和 TS 差别还是挺大的,那就通过

  • TypeScript中的函数和类你了解吗

    目录 函数 作为参数 定义函数 函数参数的类型 可选类型 参数默认值 剩余参数 this的默认推导 函数重载 类 初始化 继承 多态 成员修饰符 总结 函数 以下声明了一个函数类型,通过type来定义类型别名,void 表示没有返回值 type fnType = () => void; 作为参数 函数可以作为参数,传递到另一个函数中 type fnType = () => void; function foo(fn: fnType) { fn(); } function bar() { con

  • TypeScript中extends的正确打开方式详解

    目录 前言 extends第一式:继承 类继承类 接口继承接口 接口继承类 extends第二式:三元表达式条件判断 普通的三元表达式条件判断 情况一:Type1和Type2为同一种类型. 情况二:Type1是Type2的子类型. 情况三: Type2类型兼容类型Type1. 带有泛型的三元表达式条件判断 extends第三式:泛型约束 前言 最近完整地看了一遍TypeScript的官方文档,发现文档中有一些知识点没有专门讲解到,或者是讲解了但却十分难以理解,因此就有了这一系列的文章,我将对没有

  • 添加JavaScript重载函数的辅助方法2

    代码依然简单.所以依然没什么好解释的.. 复制代码 代码如下: /** KOverLoad 一个创建重载函数的辅助方法. 补充上次的函数. @Author ake 2010-07-03 @weblog http://www.cnblogs.com/akecn */ var KOverLoad = function(scope) { this.scope = scope || window; //默认添加方法到这个对象中.同时添加的方法的this指向该对象. this.list = {}; //存

  • JavaScript重载函数实例剖析

    1.javascript 中是没有重载函数这个概念的! 首先javascript是没有重载函数这个概念的,很久以前,我用javascript做网页的时候,写一些简单的效果,根本不需要用到重载函数,当写游戏的时候,有大量的函数的时候,就想用重载函数了,没想到javascript不支持. 我们来简单用两种方式来"模拟"下重载函数. 2.根据参数的个数来判断 javascript的函数中有一个叫arguments的变量,是记录参数的一个数组,我们可以用这个来判断参数的个数,然后分别执行不同的

  • C++类重载函数的function和bind使用示例

    在没有C++11的std::function和std::bind之前,我们使用函数指针的方式是五花八门,结构很繁琐难懂.C++11中提供了std::function和std::bind统一了可调用对象的各种操作. 1.std::function简介 std::function首先是可调用对象,本质上生成了一个类(仿函数) 简单的使用如下代码 #include <unordered_map> #include <iostream> #include <functional>

随机推荐