[TS手册学习] 03_函数相关知识点

这篇具有很好参考价值的文章主要介绍了[TS手册学习] 03_函数相关知识点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TS官方手册:TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org)

函数类型表达式

使用类似于箭头表达式的形式来描述一个函数的类型。

function greeter(fn: (a: string) => void) {
  fn("Hello, World");
}

上述代码中,fn: (a:string) => void表示变量fn是一个函数,这个函数有一个参数a,是string类型,且这个函数的返回值类型为void,即没有返回值。

调用签名

在 JS 中,函数是对象,除了可以调用也可以拥有自己的属性。而使用函数类型表达式无法声明这一部分属性的类型。

可以将函数视为一个对象,声明一个类型,其中包含多个属性的类型声明,并使用调用签名来描述函数参数和返回值的类型,取代原先函数类型表达式的写法。

type DescribableFunction = {
  description: string;
  (someArg: number): boolean;
};

在这个例子中,DescribableFunction是一个函数类型,description是这个函数类型实例对象的一个属性名,类型为string。而这个函数的参数列表类型声明为:(someArg: number),返回值类型为boolean

需要注意,在这种写法中,参数列表和返回值类型之间是用:隔开,而函数类型表达式是使用=>

构造签名

搭配构造函数使用,在调用签名的语法前面加上new

type SomeConstructor = {
  new (s: string): SomeObject;
};

泛型函数

如果函数的参数类型与返回值的参数类型存在关联,可以使用泛型:

function firstElement<Type>(arr: Type[]): Type | undefined {
  return arr[0];
}

// s是'string'类型
const s = firstElement(["a", "b", "c"]);
// n是'number'类型
const n = firstElement([1, 2, 3]);
// u是undefined类型
const u = firstElement([]);

多类型

function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func);
}

类型约束

泛型支持函数传入不同的类型,当需要约束时,例如要求传入的参数类型必须包含一个某类型的属性,则可以:

function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a;
  } else {
    return b;
  }
}

使用<Type extends { x : y}>实现,extends表示继承于类型{x:y},表示类型Type应该包含y类型的属性x

需要注意如果函数返回值类型为Type,那么不能返回类型为{x:y},因为Type包含{x:y},而可能存在比{x:y}更多的属性。

指定类型参数

function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
  return arr1.concat(arr2);
}

// 报错,因为根据第一次参数,Type会被识别为number,但是第二个参数却是string[]类型。
const arr = combine([1, 2, 3], ["hello"]);

如果执意这么设计函数的话,可以考虑使用联合类型:

const arr = combine<string | number>([1, 2, 3], ["hello"]);
使用泛型函数的建议
  1. 尽可能使用类型参数本身,而不去使用类型约束。

    // Good: 返回值类型会被推断为Type
    function firstElement1<Type>(arr: Type[]) {
      return arr[0];
    }
    // Bad: 返回值类型会被推断为any
    function firstElement2<Type extends any[]>(arr: Type) {
      return arr[0];
    }
    
  2. 尽可能少地使用类型参数。

    过多的类型参数会使得函数难以阅读,尽量确保类型参数与多个值相关(例如与函数参数和返回值都有关)再使用。

    // Good: 只用了Type一个类型参数
    function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
      return arr.filter(func);
    }
    // Bad: Func这个类型参数是多余的,只用在了一个函数参数
    function filter2<Type, Func extends (arg: Type) => boolean>(
      arr: Type[],
      func: Func
    ): Type[] {
      return arr.filter(func);
    }
    
  3. 如果类型参数只出现在一个位置,那么这个类型参数很可能不是必要的。

    使用泛型是因为函数中有若干个值的类型存在关联,如果类型参数只出现在一个位置,很可能不是必要的。

    // Bad: Str是不必要的
    function greet<Str extends string>(s: Str) {
      console.log("Hello, " + s);
    }
    // Good
    function greet(s: string) {
        console.log("Hello, " + s);
    }
    

可选参数列表

function f(x?: number) {
  // ...
}
f(); // OK
f(10); // OK

:上面的代码中x的类型实际为number|undefined,当不传入该参数的时候就是undefined

如果考虑设置默认值,如下,那么x的类型就会变成number,排除了undefined的情况。

function f(x = 10) {
  // ...
}

:只要一个参数是可选的,那么这个参数就可以被传入undefined

回调函数的可选参数

在设计一个回调函数的函数类型时,不要使用可选参数。

函数重载

function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
// 报错
const d3 = makeDate(1, 3);

如上述代码,先写两个重载函数签名(overload signatures),然后再写一个函数兼容实现这两个签名,叫做实现签名(implementation signature)。

在调用函数的时候,需要以重载签名为标准,不能以实现签名为标准。也就是说,上面这段代码中的函数makeDate,要么传入1个参数,要么传入3个参数,不能传入2个参数。

  • 从外部无法看见实现的签名。在编写重载函数时,应该始终在函数的实现之上有两个或多个签名。
  • 实现签名与重载签名之间要兼容。
  • 当可以使用联合类型函数参数解决问题时,就不要使用函数重载。

声明this的类型

const db = getDB();
const admins = db.filterUsers(function (this: User) {
  return this.admin;
});

其它与函数相关的类型

void

void作为函数的返回值类型,表示函数没有返回值。

在 JS 中没有返回值的函数会返回 undefined,但是在 TS 中undefinedvoid是不同的。

当函数返回值声明为void,仍可以在函数体中return内容,但不管返回了什么值,最终接收函数返回值的那个变量都会是void类型。

type voidFunc = ()=>void;
const f: voidFunc = ()=> true;

// 这里value的类型会被推断为void
const value = f();
object

object类型是除了stringnumberbigintbooleansymbolnullundefined的其它类型。

object类型与空对象类型{}不同,与全局类型Object也不同。永远不要使用Object类型,而是使用object

在 JS 中,函数也是对象;在 TS 中,函数也被认为是object类型。

unknown

unknownany非常类似,但是unknown更安全。

因为unknown类型变量的任何操作都是非法的,这迫使大多数操作之前需要对unknown类型变量进行类型的检查。

any类型的值执行操作之前不需要进行任何检查。

function f1(a: any) {
  a.b(); // OK
}

function f2(a: unknown) {
  a.b(); // ERROR: 'a' is of type 'unknown'.
}

unknown类型只能赋值给anyunknown类型。

unknown类型的意义:TS 不允许我们对类型为 unknown 的值执行任意操作。我们必须首先执行某种类型检查以缩小我们正在使用的值的类型范围。

可以使用类型收束(Narrowing)的操作将unknown缩小到具体的类型,再进行后续操作。

never

never通常描述返回值类型,表示永远不返回值。与void不同,使用never意味着函数会抛出一个异常,或者程序会被终止。

function fail(msg: string): never {
  throw new Error(msg);
}

另一种情况下也会出现never,就是当联合类型被不断收窄到空时,就是never

function fn(x: string | number) {
  if (typeof x === "string") {
    // do something
  } else if (typeof x === "number") {
    // do something else
  } else {
    x; // 这里x的类型是'never'
  }
}
Function

全局类型Function声明的变量包含了 JS 中函数所拥有的所有属性和方法,例如bindcallapply

Function声明的变量是可执行的,并且返回any

这种函数类型声明方式很不安全,因为返回any,最好使用函数类型表达式声明:()=>void

function doSomething(f: Function) {
  return f(1, 2, 3);
}

不定长参数列表

在 TS 中,不定长参数列表的类型应该被声明为Array<T>T[]或元组类型。

function multiply(n: number, ...m: number[]) {
  return m.map((x) => n * x);
}

spread语法可以展开可迭代对象(例如数组,对象)变成不定长的参数列表。例如push函数可以接收多个参数。

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2);

但需要注意,TS 认为数组是可变的,数组长度是可变的。

观察下面的案例代码:

const args = [8, 5];
const angle = Math.atan2(...args);

尽管Math.atan2接收两个number类型的参数,而args也刚好是长度为2的number[]类型数组,展开后刚好。

但是这段代码会报错,因为数组是可变的。

一种较为直接的解决方法是使用const

// 视为长度为2的元组
const args = [8, 5] as const;
// 现在不会报错了
const angle = Math.atan2(...args);

参数解构的类型声明

function sum({ a, b, c }: { a: number; b: number; c: number }) {
  console.log(a + b + c);
}

或者使用type简化:文章来源地址https://www.toymoban.com/news/detail-747558.html

type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) {
  console.log(a + b + c);
}

到了这里,关于[TS手册学习] 03_函数相关知识点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AWS SAA-C03考试知识点整理

    S3: 不用于 数据库 功能 分类: S3 Standard :以便频繁访问 S3 Standard-IA 或 S3 One Zone-IA : 不经常访问的数据 Glacier: 最低的成本归档数据 S3 Intelligent-Tiering智能分层 :存储具有不断变化或未知访问模式的数据 S3 存储 也可用于静态网站托管 bucket名::amazonaws.com S3 存储 L ens :

    2024年02月08日
    浏览(35)
  • 【字节面试】Fail-fast知识点相关知识点

    字节面试,问到的一个小知识点,这里做一下总结,其实小编之前有一篇文章,已经对此有过涉及,不过这里知识专项针对于问题,把这个知识点拎出来说一下。 什么是Fail-fast机制? Hashmap是否拥有Fail-fast机制? ConcurrentModificationException异常原因和解决方法是什么? 哪些你常

    2024年01月22日
    浏览(35)
  • Python的知识点运用-2(排序&&找差值及修正ts合成顺序)

    本章内容,涉及到上一章的视频爬虫,但是问题不大。最主要还是基础内容。 基础内容:排序,找出缺失值。 学习本章的前,我是建议去跑一遍gitee上的代码的。 排序问题由来 视频获取后,根据命名,排序是错的。问题除了命名以外还有一个因素就是多线程并发的原因。

    2023年04月09日
    浏览(25)
  • java相关知识点

    1.String和StringBuffer如何互相转化 StringBuffer buffer = new StringBuffer(string); String string = buffer.toString();  2.如何实现两个数组内容的拷贝  3.如何去除字符串首尾空格 str.trim()  4.字符串和字符数组如何相互转换 字符串转字符数组:str.toCharArray(); 字符数组转字符串:strs.valueOf(char[] ch)  

    2023年04月23日
    浏览(35)
  • MicroBlaZe 相关知识点

    1.DDR3——存储.c的应用程序。需要两个时钟(200MHZ输入,还有一个是特权同学的166.6m) 2.QSPI FLASH——对flash进行固化(1.需要50M外部时钟输入2.在SDK里面需要修改值为5)。 3.MicroBlaZe的输入时钟(mig输出的时钟频率一般小于200MHZ)。 5.SDK里面会有个串口terminal可以显示打印信息。

    2024年02月13日
    浏览(41)
  • JVM相关知识点

    Java可以跨平台的原因是因为它使用了Java虚拟机(JVM)作为中间层。Java源代码首先被编译成字节码,然后由JVM解释执行或即时编译成本地机器代码。这样,在不同的操作系统上,只需要安装适合该操作系统的JVM,就可以运行相同的Java程序。JVM提供了一个抽象的执行环境,使得

    2024年02月08日
    浏览(37)
  • Hadoop相关知识点

    开启防火墙 sudo ufw enable 关闭防火墙 sudo ufw disable 查看防火墙状态 sudo ufw status 修改主机名 sudo vi /etc/hostname 修改映射 sudo vi /etc/hosts (考题) 建立文件夹 mkdir 文件夹名字 删除文件夹 rm -rf 递归删除文件夹向下穿透,其下所有文件、文件夹都会被删除 rm -f 强制删除文件 rm -r 递归

    2024年02月06日
    浏览(32)
  • SpringMVC相关知识点

    传统开发中的控制层: 接收请求参数 request.getParameter 封装实体 new 实体类调用其set方法 访问业务层 接收访问结果 指派页面 通过request和response对象进行页面跳转 将共有行为进行抽取成DispatcherServlet【SpringMVC内部集成】,通过Spring-MVC.xml配置文件去配置。 Spring: 获取请求参数

    2024年02月16日
    浏览(36)
  • http相关知识点

    一张网页实际上可能会有多种元素组成,这也就说明了网页需要多次的http请求。 可由于http是基于TCP的,而TCP创建链接是有代价的,因此频繁的创建链接会导致效率降低 为了防止这种情况,就需要两端主机都具备支持长连接的功能,将大份的资源使用一条链接就包含,也就是

    2024年02月13日
    浏览(34)
  • Linux相关知识点

    Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。 Linux内核 是一个Linux系统的内核,而不是一个操作系统 Linux操作系统 红帽操

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包