Typescript 函数类型详解

news2025/7/15 21:01:18

Typescript 函数

前言

虽然 JS/TS 支持面向对象编程,但大部分时候还是在写函数。函数是一等公民。本文介绍下如何在 TypeScript 中使用函数,包括:

  • 函数类型声明
  • 函数参数类型:可选参数、默认参数、剩余参数
  • 函数返回值类型
  • this 类型
  • 函数重载

函数类型

面试中经常会被问到,JS 中有哪几种数据类型。其中就会有函数类型。

JS 中的函数类型很模糊,准确来说,仅有类型的概念,却无类型的实质。好在有了 TS 强类型的加持,现在可以好好定义一个函数的类型了。

声明一个函数类型,有若干种不同的方式。比如通过 interface 定义函数类型,通过 type 声明函数类型别名,在类声明中声明函数类型等等。

但核心就一点,只关注函数参数的类型返回值的类型

下面就从函数的声明入手,来看看函数类型的使用。

函数的声明方式

有三种最简单的函数声明方式。

使用 function 关键字进行声明:

function add(a: number, b: number): number {
  return a + b
}

通过函数表达式进行声明:

let add = function (a: number, b: number): number {
  return a + b
}

或者使用箭头函数:

let add =  (a: number, b: number): number => {  
    return a + b
}

上面这三种声明函数的方式和 JS 中声明函数别无二致,就是多了两点:

  • 函数参数需要给明类型
  • 函数返回值也需要给出类型

那么函数类型到底在哪里呢?把鼠标移动到函数名字上就能看到了:

image-20221114151636908

image-20221114151710177

image-20221114152126540

和声明普通变量变量一样:

let name = 'kunwu'

如果没有使用类型注解,那么编译器会自动推导出类型来。上面红框标识出来的类型,就是编译器推导出来的。

函数的类型注解

函数的类型形如 (参数:类型) => 类型,所以函数的类型注解就是:

let add: (a: number, b: number) => number = function (a, b) {
  return a + b
}

通常函数的类型都比较长,此时可以使用 type 类型别名,来声明一个标识符表示该类型:

type Add = (a: number, b: number) => number

let add: Add => number = function (a, b) {
  return a + b
}

这样,声明函数类型,使用函数类型,看上去就很简洁直观了。

对象中的函数类型

函数的参数

声明函数时,可以使用类型注解声明参数类型。如果不指定类型,默认类型是 any

function add (a: number, b: number) :number {
    return a + b
}

image-20221115004807260

可选参数

可选参数使用 ? 标记,需要放到固定参数的后面:

const fn = (a: number, b?:number) => {
    if(b) {
        return a + b
    } else {
        return a
    }
}

可选参数意味着参数可传可不传。通过编译器的类型推导,可以看到好像可选参数等同于一个联合类型:

image-20221115004923924

但其实并不等同。

可选参数表示参数可传可不传,若传则必须是指定的类型。

而直接将参数类型声明为 string|undefined,意味着这是个必传参数,必须传实参。

参数默认值

参数的默认值,在参数的类型后面使用 = 声明:

const fn = (a: number, b: number = 10): number => {
    return a + b
}

剩余参数

剩余参数是 ES6 中的一个特性,使用剩余运算符 ... 来获取函数实参中未被形参声明的变量,其取得的值是一个数组,比如:

function add(a,b, ...args) {
    console.log(args)
}

add(1,2,3,4,5)

则剩余参数 args 就等于 [3, 4, 5]。

TS 中剩余参数也要有类型声明,需要将其声明为数组类型或者元组类型。

function add(a: number, b: number, ...args: number[]) {
    console.log(c)
}

剩余参数和其他的固定参数不同。其他的固定参数声明了类型,则必须传该类型的值。而剩余参数虽然也声明了类型,但可传可不传,可传一个,可传多个,比如:

function add(a: number, b: number, ...args: number[]) {
    console.log(args)
}

add(1, 2) // [ ]
add(1, 2, 3) // [ 3 ]
add(1, 2, 3, 4) // [ 3, 4 ]

还可以将剩余参数类型声明为元组类型,元组中还可以继续使用可选参数,在参数后使用 ? 表示:

function log( ...args: [string, number, boolean?]) {
    console.log(args)
}

log('Shinichi', 17) // [ 'Shinichi', 17 ]
log('Zoro', 19, true) // [ 'Zoro', 19, true ]

函数的返回值类型

函数的返回值类型可以通过类型注解指定。如果不指定的话,TS 编译器能够根据函数体的 return 语句自动推断出返回值类型,因此我们也可以省略返回值类型。

TS 基本类型中有一个 void 类型,表示空类型,它唯一的用处就是用作函数的返回值类型。当一个函数没有 return 语句时,

image-20221115125205523

如果函数使用 return 语句返回了 undefined 值,则返回值类型就为 undefined 而不是 void 了:

image-20221115125323627

但是此时可以将返回值类型使用类型注解指定为 void:

image-20221115125425635

this 类型

JS 函数中到处可见 this 的身影。关于 this 的指向也是前端八股中的基础之基础。

默认情况下 TS 编译器会将函数中的 this 设为 any 类型,也就是说编译器不会对 this 做类型检查,就可以任意使用 this,比如:

function fn() {
    this.name = 'Naruto'
    this.age = 18
}

同时 TS 编译器又提供了一个编译选项 --noImplicitThis,开启后会检查 this 的类型,此时需要明确指定其类型,否则会报错,如下:

image-20221115150823423

那么如何为 this 声明类型呢?

声明 this 类型

TS 函数中有一个特殊的 this 参数,它用来指定该函数中用到的 this 的类型,需要定义在形参的第一个位置。

还是上面的例子,要为函数中的 this 指定类型的话,这样写:

function fn(this: {name: string, age: number}) { 
  this.name = 'Naruto'
  this.xxx = 'xxx'
}

直接在函数参数列表中声明 this 类型不太优雅,可以使用 type 关键字声明别名再使用:

type Person = {name: string, age: number}

function fn(this: Person) { 
  this.name = 'Naruto'
  this.age = 18
}

当定义了 this 类型后,函数在调用时也会有所不同,需要使用 call、apply :

type Person = {name: string, age: number}

function fn(this: Person, a: number) { 
  this.name = 'Naruto'
  this.age = 18
}


fn.call({name: 'Naruto', age: 18}, 10)

fn.apply({name: 'Naruto', age: 18}, [10])

像以前那样直接调用函数是错误的:

fn(10) // X

函数重载

面向对象编程有三大特征,封装、继承和多态。多态的表现之一就是函数的重载。

函数重载,就是可以多次声明一个同名函数,但是它们的参数类型不同或者参数个数不同。这样在调用时,可以根据传入参数类型的不同,参数个数的不同,来确定执行的到底是哪一个函数。

函数重载是后端语言的概念,比如 java 中:

// 两个整数的和
public static int add(int a, int b)  {
  return a+b;
}

// 三个整数的和
public static int add(int a, int b, int c) {
 return add(a,b)+c;
}

JS 本身并不支持函数重载。如果多次声明一个函数,则后声明的会覆盖掉先声明的。但是 JS 可以利用 arguments 对象,再加上判断实参的类型,来模拟重载的功能,比如:

function add() {
   let args = Array.from(arguments)
   if(args.length == 2) {
       return args[0] + args[1]
   } else if(args.length == 3) {
        return args[0] + args[1] + args[3]
   }
}

add(1,2)
add(1, 2, 3)

TS 中多次声明一个同名函数,编译器会报错。但是 TS 提供了实现函数重载的方法:先通过 function 关键字声明重载的类型,最后写函数的实现。

function add(a: number, b: number) : number

function add(a: string, b: string) : string

function add(a: number|string, b: number | string) {
  if(typeof a === 'number' && typeof b === 'number') {
    return a + b
  }  else if(typeof a === 'string' && typeof b === 'string') {
    return a + b
  } 
}

add(1, 2)
add('10', '20')

由于在声明重载时已经确定了函数的返回值类型,在写函数实现时,就不再需要写返回值类型了。编译器会根据重载类型自动推导。

TS 的函数重载只是一种伪重载,最终还是要靠去判断类型,来执行不同的逻辑。

还有一点要注意,声明函数重载和函数实现必须写在一块,中间不能插入其他语句。

总结

本文介绍了TS 中有关函数的知识,包括函数的声明方式,如何声明函数类型,函数参数和返回值的类型,函数重载以及 this 的类型。大部分内容和 JS 中差不太多,主要是 this 类型和函数重载这两点,需要额外关注下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/8466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java#5(数组)

目录 数组 1.数组的完整格式:数据类型[] 数组名 new 数据类型[]{元素1,元素2......}; 2.数组的简化格式:数据类型[] 数组名 {元素1,元素2......}; 3.数组的地址​编辑 4.数组的索引(下标,角标) 5.length的使用(表示数组的长度:有几个元素) 6.数组动态初始化:初始化时指…

Redis事务入门及命令

文章目录Redis 事务入门及命令事务概念Redis 事务概念Redis 事务特性Redis 三个阶段入门代码示例Redis 相关命令MULTIDISCARDEXECWATCHUNWATCHRedis 事务入门及命令 事务概念 数据库事务( transaction )是访问并可能操作各种数据项的一个数据库操作序列,这些操作要…

详解 YUV,一文搞定 YUV 是什么!

YUV 是一个颜色模型,通常用作彩色图像管道的一部分。它对彩色图像或视频进行编码时考虑到了人类的感知,与“直接”的 RGB 表示相比,允许减少色度分量的带宽。历史上,术语 YUV 和 Y’UV 用于电视系统中颜色信息的特定模拟编码。今天…

HTML学生作业网页:使用HTML+CSS技术实现传统文化网页设计题材-西安事变历史纪念馆 10页 带视频 带音乐

Web前端开发技术 描述 网页设计题材,DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 茶文化网站 | 中华传统文化题材 | 京剧文化水墨风书画 | 中国民间年画文化艺术网站 | HTML期末大学生网页设计作业 HTML:结构 CSS:样式 在操作方面上运…

《上海悠悠接口自动化平台》-4.注册用例集实战演示

前言 以注册接口为例,在平台上演示如何维护接口自动化用例 访问地址http://47.108.155.10/login.html 用户名: demo, 密码: demo123 有兴趣的可以自己去查看用例规范 和 运行效果。 API 接口层 先找出注册接口的接口文档,以下是接口文档部分 主要关…

Redis配置哨兵及其机制

目录一、Redis哨兵诞生背景二、关于哨兵三、哨兵机制的基本流程3.1 监控3.2 选主3.3 通知四、关于主观下线和客观下线4.1 主观下线4.2 客观下线五、选主规则3.1 优先级最高的从库得分高3.2 和旧主库同步程度最接近的从库得分高3.3 ID 号小的从库得分高六、配置流程七、总结一、…

网络面试-0x10地址栏输入URL敲入回车后发生了什么?

一、 URL解析 1、 首先判断你输入的是一个合法的URL还是待搜索的关键字 2、如果是URL,对URL进行解析 二、 DNS查询 1、设备 —— 本地DNS服务器 —— xx 递归过程 2、DNS服务器和 顶级域名服务器、二级域名服务器、权威域名服务器之间是迭代过程。 三、 TCP连接 …

redis和selery相关知识点

目录标题一:redis字符串操作二:redis hash操作三:redis列表操作四:redis管道1.redis数据库,是否支持事务?2.redis代码实现事务五:redis其他操作六:django中集成redis1.方式一:直接使…

用python就获取到照片拍摄时的详细位置【源码公开】

文章目录一.引言1.读取照片信息,获取坐标2.通过baidu Map的API将GPS信息转换成地址。二.源码附上!!!注意事项一.引言 先看获取到的效果 拍摄时间:2021:12:18 16:22:13 照片拍摄地址:(内蒙古自治区包头市昆都仑区, 内…

pytorch从零开始搭建神经网络

目录 基本流程 一、数据处理 二、模型搭建 三、定义代价函数&优化器 四、训练 附录 nn.Sequential nn.Module model.train() 和 model.eval() 损失 图神经网络 基本流程 《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili1. 数据预处理(Dataset、…

由浅入深,一起来刷Java高级开发岗面试指南,明年面试必定无忧!

前言 我只想面个CV工程师,面试官偏偏让我挑战造火箭工程师,加上今年这个情况更是前后两男,但再难苟且的生活还要继续,饭碗还是要继续找的。在最近的面试中我一直在总结,每次面试回来也都会复盘,下面是我根…

为啥50岁以后,病就增多了?中老年人想要少生病,该做些什么?

人到中年,生活会有很多变化,很多男性朋友从以前别人口中的小伙子,变成现在家里的顶梁柱,很多以前别人口中的小姑娘,变成现在的贤妻良母,或者拥有自己的一番事业。角色在变化的同时,身体情况也发…

高压电气系统验证

纯电和混合动力汽车中的高压电气系统关乎整车的能耗和安全,需要在部件及整车开发阶段做全面的测试与验证。符合ISO 21498*标准的电压、电流一体式测量模块CSM HV BM系列产品,可以直接串联在整车级别的高压电气线缆中,安全可靠的完成高压电气系…

java面试强基(2)

字符型常量和字符串常量的区别? 形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。 含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。 占内存大小 &…

SpringCloud 核心组件Feign【远程调用自定义配置】

目录 1,Feign远程调用 1.1:Feign概述 1.2:Feign替代RestTemplate 1):引入依赖 2):添加注解 3):编写Feign的消费服务,提供服务 4):测…

C. Discrete Acceleration(浮点二分)

Problem - 1408C - Codeforces 题意: 有一条长度为l米的道路。路的起点坐标为0,路的终点坐标为l。 有两辆汽车,第一辆站在路的起点,第二辆站在路的终点。它们将同时开始行驶。第一辆车将从起点开到终点,第二辆车将从终点开到起…

通俗易懂的React事件系统工作原理

前言 React 为我们提供了一套虚拟的事件系统,这套虚拟事件系统是如何工作的,笔者对源码做了一次梳理,整理了下面的文档供大家参考。 在 React事件介绍 中介绍了合成事件对象以及为什么提供合成事件对象,主要原因是因为 React 想…

【附源码】Python计算机毕业设计图书商城购物系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,我…

MongoDB学习一:相关概念和单机部署

目录一、MongoDB 应用场景:二、什么时候使用MongoDB:三、MongoDB简介:四、体系结构:五、数据模型:六、MongoDB的特点:七、MongoDB单机部署一、MongoDB 应用场景: 二、什么时候使用MongoDB&#…

对FD描述符(包括inode以及三张表)的一点理解

文件描述符,简单来说是一个从0开始递增的非负整数。 具体来说是linux/unix对文件系统的一种底层抽象,这种抽象是通过三张表来实现的。 这三张表分别是: 1.进程级的文件描述符表;(文件标志位/文件指针) 2.系统级的打开文件描述…