彻底理解TypeScript函数语法

news2024/11/27 20:30:13

目录

  • 参数类型
    • 基本声明
    • 默认参数
    • 剩余参数
    • 可选只读
    • 匿名函数
    • 回调函数
  • 返回值类型
  • 函数类型
    • 表达式
    • 调用签名
    • 构造签名
  • 函数的重载
  • this
    • 可推导的
    • 编译选项
    • this类型
    • 内置工具

函数是JavaScript非常重要的组成部分,TypeScript中也是如此,TypeScript 提供了强大的类型系统来帮助我们定义函数的参数、返回值以及函数本身的类型

参数类型

基本声明

参数的类型注解:声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型

function add(num1: number, num2: number) {
  console.log(num1,num2)
}
add(10, 20)
add('10', '20') // Argument of type 'string' is not assignable to parameter of type 'number'

默认参数

如果调用时没有传递该参数,则使用默认值,这个时候greeting的类型其实是 undefinedstring 类型的联合

function greet(name: string, greeting: string = "Hello") {
  return `${greeting}, ${name}!`;
}

console.log(greet("Alice"));              // Hello, Alice!
console.log(greet("Alice", "Good day"));  // Good day, Alice!

剩余参数

使用剩余参数可以让函数接收任意数量的参数,剩余参数会被收集到一个数组中

function sum(...numbers: number[]) {
  return numbers.reduce((acc, num) => acc + num, 0);
}

console.log(sum(1, 2, 3, 4)); // 10

可选只读

  • 可以指定某个参数是可选的,可选类型需要在必传参数的后面,这个参数z依然是有类型的,类型是:number | undefined

    function fo1(x: number, y: number, z?: number) { 
      console.log(x, y, z) // 10 20 undefined
    }
    fo1(10, 20)
    
  • readonly 关键字主要用于对象和数组等复合类型的参数,而对于普通的基本类型(如 number, string 等),它们是按值传递的,没必要使用 readonly

    function foo2(data: { name: string, readonly age?: number }) { 
      console.log(data)
    }
    

匿名函数

匿名函数与函数参数声明会有一些不同:

  • 当一个函数出现在TypeScript可以确定该函数会被如何调用的地方时,该函数的参数会自动指定类型

  • 这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型

const names: string[] = ['abc','cba','eee','ghj']
names.forEach((n => { // 这个n就是string类型,不需要在指定类型
  console.log(n.toLocaleUpperCase())
}))

回调函数

函数可以作为函数的参数回调,TypeScript对于传入的函数类型的多余的参数会被忽略掉

function executeCallback(callback: (message: string) => void) {
  callback("This is a callback message");
}

executeCallback((msg: string) => {
  console.log(msg);  // 输出: This is a callback message
});

返回值类型

  • 可以添加返回值的类型注解,这个注解出现在函数列表的后面,返回的类型不对会报错
    在这里插入图片描述

  • 和变量的类型注解一样,通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型
    在这里插入图片描述

函数类型

表达式

  • 可以编写函数类型的表达式(Function Type Expressions),来表示函数类型 (参数列表) => 返回值类型

  • 在某些语言中,可能参数名称num1num2是可以省略,但是TypeScript是不可以的

  • (x: number, y: number) => number 是函数的类型签名,它表示该函数接受两个 number 类型的参数并返回一个 number
    在这里插入图片描述

type mulType = (num1: number, num2: number) => number

const mul: mulType = function (num1: number, num2: number){
  return num1 * num2
}
mul(10,20)

调用签名

函数的调用签名(Call Signatures 是从对象的角度来看待这个函数, 函数也可以有其他属性)

/* 作为函数类型 */
interface ICacl {
  key: string;
  (num1: number, num2: number): void;
}

const cacl: ICacl = function(num1: number, num2: number): void {
  console.log(num1, num2);
};

// 给函数对象赋予属性 key,不赋值会报错
cacl.key = "someKey";
console.log(cacl.key);  // 输出: "someKey"
cacl(10, 20);  // 输出: 10 20


/* 作为参数 */
interface ISign {
  key: string,
  (num1: number, num2: number): void
}
function sum(num: number, callBack: ISign) {
  console.log(callBack.key)
  callBack(num, 20)
}
const fn: ISign = (num1: number, num2: number) => { }
fn.key = 'params'
sum(10, fn)

构造签名

构造签名(constructor signature)是用于定义类的构造函数类型的语法,定义一个对象或类可以被实例化,描述了使用 new 关键字实例时所需的参数和返回的实例类型

interface IPerson {
  new (name: string, age: number): Person
}
class Person {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
let obj:IPerson = Person
console.log(new obj('obj', 18))

函数的重载

  • TypeScript中,可以去编写不同的重载签名(overload signatures)来表示函数可以以不同的方式进行调用

  • 一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现

  • 调用时它会根据传入的参数类型来决定执行函数体时,到底执行哪一个函数的重载签名

/* 
  在TypeScript中,如果编写一个add函数,希望可以对字符串和数字类型进行相加,应该如何编写呢?
*/
function add1(a1: string | number, a2: string | number, a3: string | number) {
  return a1 + a2 + a3 // 报错:运算符“+”不能应用于类型“string | number”和“string | number”
}

// 编写不同的重载签名
function add(a1: number, a2: number, a3: number): number
function add(a1: string, a2: string): string
function add(a1: any, a2: any, a3?: any): any {
  return a1 + a2 + a3
}
console.log(add(10, 20, 30)); // 60
console.log(add("aaa", "bbb")); // aaabbbundefined

this

thisJavaScript中一个比较难以理解和把握的知识点,目前的Vue3React开发中你不一定会使用到thisVue3Composition API中和ReactHooks开发中很少见到this,但是还是要简单掌握一些TypeScript中的this

可推导的

默认情况下TypeScript在编译时,this是可以正确去使用的,因为在没有指定this的情况,this默认情况下是any类型的

const bar = {
  name: 'bar',
  foo: function (){
    console.log(this.name)
  }
}
bar.foo()
function foo(){
  console.log(this)
}

编译选项

  • 使用命令tsc --init生成tsconfig.json的配置文件时,有的this就会报错

  • 主要由tsconfig.js中的 noImplicitThis 值控制

  • 设置了noImplicitThistrue时, TypeScript会根据上下文推导this,但是在不能正确推导时就会报错,需要明确的指定this

const bar = {
  name: 'bar',
  foo: function (){
    console.log(this.name) // 可以类型推导出this: { name: string; foo: () => void; }
  }
}
bar.foo()

function foo(){
  console.log(this) // 这时推导不出this的具体类型,修改tsconfig.json中的 noImplicitThis值为 false 就不会报错
}
foo()

this类型

在开启noImplicitThis的情况下,必须指定this的类型:

  • 函数的第一个参数可以根据该函数之后被调用的情况,用于声明this的类型(名词必须叫this

  • 在后续调用函数传入参数时,从第二个参数开始传递的,this参数会在编译后被抹除

const bar = {
  name: 'bar',
  foo: function (){
    console.log(this.name) // 可以类型推导出this: { name: string; foo: () => void; }
  }
}
bar.foo()

function foo(this: {name: string, age: number}, num: number){
  console.log(this, num) // 打印:name: 'foo', age: 18} 20    这时this的具体类型就是 {name: string, age: number}
}
foo.call({name: 'foo', age: 18}, 20)

内置工具

Typescript 提供了一些this相关的工具来辅助进行常见的类型转换,这些类型全局可用:

  • ThisParameterType<Type>:用于从函数类型中提取 this 参数的类型,如果函数没有明确指定 this 参数,那么 ThisParameterType 会解析为 unknown

    function foo1(this: {name: string, age: number}, num: number){
      console.log(this, num) // 打印:name: 'foo', age: 18} 20    这时this的具体类型就是 {name: string, age: number}
    }
    foo1.call({name: 'foo', age: 18}, 20)
    type thisType1 = ThisParameterType<typeof foo1> // type thisType = { name: string; age: number;}
    
    
    function foo2(num: number){
      console.log(num)
    }
    foo2(20)
    type thisType2 = ThisParameterType<typeof foo2> // type thisType2 = unknown
    
  • OmitThisParameter<Type>:从函数类型 Type移除 this 参数。如果 Type 没有 this 参数,或者 Type 不是一个函数类型,那么 OmitThisParameter<Type> 返回 Type 本身

    function foo1(this: {name: string, age: number}, num: number){
      console.log(this, num) // 打印:name: 'foo', age: 18} 20    这时this的具体类型就是 {name: string, age: number}
    }
    foo1.call({name: 'foo', age: 18}, 20)
    type fnType1 = OmitThisParameter<typeof foo1> // type fnType1 = (num: number) => void
    
    
    function foo2(num: number){
      console.log(num)
    }
    foo2(20)
    type fnType2 = OmitThisParameter<typeof foo2> // type fnType2 = (num: number) => void
    
    type fnType3 = OmitThisParameter<string> // type fnType3 = string
    
  • ThisType<T>:这个类型不返回一个转换过的类型,它被用作标记一个上下文的this类型

    • ThisType 只能用于对象字面量,它不能在类或函数中直接使用

    • ThisType<T> 本身并不会在对象里定义 this,它只是告诉 TypeScript 如何推断 this 的类型

    • 需要与 TypeScriptnoImplicitThisnoImplicitAny 编译选项一起使用,确保 this 是明确的

    interface IState {
      name: string
      age: number
    }
    interface IData {
      state: IState
      running: () => void
    }
    const info1: IData = {
      state: {
        name: 'info1',
        age: 18,
      },
      running() {
        console.log(this) // 这时的this类型推断为是IData,但它应该是IState 打印:{name: 'info1', age: 18}
      }
    }
    info1.running.call(info1.state)
    
    const info2: IData & ThisType<IState> = {
      state: {
        name: 'info2',
        age: 18,
      },
      running() {
        console.log(this) // 这时的this类型是对的是IState,打印:{name: 'info2', age: 18}
      }
    }
    // 需要手动绑定 this 到 state,因为ThisType<IState> 仅仅是一个上下文类型提示工具,而不会直接影响运行时的 this 绑定
    info2.running.call(info2.state)
    

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

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

相关文章

网关在不同行业自动化生产线的应用

网关在不同行业自动化生产线的应用&#xff0c;展示了其作为信息与物理世界交汇点的广泛影响力&#xff0c;尤其在推动行业智能化、自动化方面发挥了不可估量的作用。以下是网关技术在污水处理、智慧农业、智慧工厂、电力改造及自动化控制等领域的深入应用剖析。 1. 污水处理 …

盒子模型的简单运用

1.块内元素与行内元素 HTML_code <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</titl…

Scala面试题大全~基础题(15题)

1&#xff1a;Scala是什么? Scala是一种多范式的编程语言&#xff0c;它结合了面向对象编程和函数式编程的特性&#xff0c;它支持面向对象、函数式和命令式编程方法。Scala运行在Java虚拟机&#xff08;JVM&#xff09;上&#xff0c;这意味着它可以与Java代码无缝集成。它还…

【多版本并发控制(MVCC)】

并发事务问题&#xff1a; MySQL隔离级别-未提交读&#xff0c;提交读&#xff0c;可重复读&#xff0c;序列化 隔离级别对于并发事务的解决情况 隔离级别脏读不可重复读幻读未提交读不可不可不可读已提交可不可不可可重复读 &#xff08;默认&#xff09;可可不可串行化&…

现货黄金价格走势图策略分析 先看“势”

在现货黄金投资市场&#xff0c;对金价走势图的趋势进行分析&#xff0c;是投资者做出明智决策的关键步骤。通过有效的趋势分析&#xff0c;投资者可以更好地预测市场的走向&#xff0c;从而制定相应的交易策略。本文将详细介绍如何分析金价的趋势&#xff0c;并探讨这种分析方…

J1学习打卡

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 # 数据预处理和加载 import torch from torch import nn, optim from torch.utils.data import DataLoader from torchvision import datasets, transforms, …

Python | Leetcode Python题解之第470题用Rand7()实现Rand10()

题目&#xff1a; 题解&#xff1a; class Solution:def rand10(self) -> int:while True:a rand7()b rand7()idx (a - 1) * 7 bif idx < 40:return 1 (idx - 1) % 10a idx - 40b rand7()# get uniform dist from 1 - 63idx (a - 1) * 7 bif idx < 60:retur…

C语言 | Leetcode C语言题解之第472题连接词

题目&#xff1a; 题解&#xff1a; typedef struct Trie {struct Trie * children[26];bool isEnd; }Trie;#define TRIE_INITIAL(node) do { \for (int i 0; i < 26; i) { \(node)->children[i] NULL; \} \(node)->isEnd false; \ }while(0);static void freeTri…

仿IOS桌面悬浮球(支持拖拽、自动吸附、自动改变透明度与点击、兼容PC端与移动端)

使用 pointerdown/pointermove/pointerup 实现仿IOS桌面悬浮球效果&#xff0c;支持拖拽、指定拖拽选对容器&#xff0c;指定拖拽安全区、自动吸附、自动改变透明度与点击&#xff0c;兼容PC端与移动端。 效果展示 https://code.juejin.cn/pen/7423757568268304421 代码实现 …

(27)QPSK信号在非相关平坦莱斯(Rician)衰落信道上的误码率性能MATLAB仿真

文章目录 前言一、Rician衰落信道模型的MATLAB代码二、在非相关的平坦Rician衰落信道上传输QPSK符号模型1.MATLAB仿真代码2.仿真结果 前言 本文首先给出莱斯衰落信道的建模函数&#xff0c;然后基于该函数给出在非相关的平坦Rician衰落信道上传输QPSK数字调制符号的MATLAB仿真…

【OpenCV】基础操作学习--实现原理理解

读取和显示图像 基本操作 cv2.imread(filename , flags)&#xff1a;文件中读取图像&#xff0c;从指定路径中读取图像&#xff0c;返回一个图像数组&#xff08;NumPy数组&#xff09; filename&#xff1a;图像文件的路径flags&#xff1a;指定读取图像的方式 cv2.IMREAD_COL…

IP地址我个人的理解

作为连IP地址都没弄懂的一个网络小白&#xff0c;有时候开发以及建站会接触到IP、DNS等等概念&#xff0c;所以说有必要去查询一下相关知识内容&#xff0c;羞耻地说其实我是有一个计算机网络技术三级证书&#xff0c;但是这个啥用没有死记硬背就行了&#xff0c;许多知识点不能…

软件工程pipeline梳理

文章目录 软件工程pipeline梳理为什么需要梳理软件工程的pipeline软件工程pipeline的概念与注意点软件工程pipeline中的最大挑战rethink相关资料 软件工程pipeline梳理 为什么需要梳理软件工程的pipeline 反思自己日常工作中的认知和行为。以算法/软件工程师为代表的技术工种往…

2024-10-10 问AI: [AI面试题]激活函数在神经网络中的作用是什么?

文心一言 激活函数在神经网络中扮演着至关重要的角色。它们的主要作用包括&#xff1a; 引入非线性&#xff1a; 神经网络中的每一层通常是由线性变换&#xff08;如权重矩阵乘以输入向量再加上偏置&#xff09;构成的。如果没有激活函数&#xff0c;多层神经网络将仅仅是一个…

正点原子讲解SPI学习,驱动编程NOR FLASH实战

配置SPI传输速度时&#xff0c;需要先失能SPI,__HAL_SPI_DISABLE,然后操作SPI_CR1中的波特率设置位&#xff0c;再使能SPI, NM25Q128驱动步骤 myspi.c #include "./BSP/MYSPI/myspi.h"SPI_HandleTypeDef g_spi1_handler; /* SPI句柄 */void spi1_init(void) {g_spi…

前端基础(四十):拖放功能的实现

效果 源码 <div class"draggable-wrap"><div class"draggable-box" draggable"true" data-json{"name": "Lee"}><h1>Lee</h1><div class"drop-box" data-json{"name": &qu…

API网关之Hango

Hango 是基于云原生和服务网格技术的开源 API 网关&#xff0c;专为现代分布式系统设计&#xff0c;提供高效、安全、可扩展的流量管理解决方案。Hango 网关是基于 Envoy Proxy 构建的&#xff0c;能够处理复杂的微服务架构中流量控制、服务治理和安全需求。Hango 强调与 Kuber…

Java | Leetcode Java题解之第472题连接词

题目&#xff1a; 题解&#xff1a; class Solution {Trie trie new Trie();public List<String> findAllConcatenatedWordsInADict(String[] words) {List<String> ans new ArrayList<String>();Arrays.sort(words, (a, b) -> a.length() - b.length(…

大模型1-本地部署实现交互问答

任务 在本地部署大模型&#xff0c;调用大模型进行对话。 添加库&#xff1a; 1、Transformer Transformers 是由 Hugging Face 开发的一个开源库&#xff0c;广泛应用于自然语言处理&#xff08;NLP&#xff09;任务。其主要功能是简化了对大型预训练语言模型的加载和使用…

神经网络整体架构

文章目录 1.输入层Input2.卷积层Conv3.激活函数层(一)Sigmoid 函数(二)Tanh 函数(三)修正线性单元ReLU(四)Leaky ReLU函数(带泄露的Relu)(五)参数化ReLU 4.池化层POOL5.全连接层FC6.输出层Output 用全连接神经网络处理大尺寸图像具有三个明显的缺点&#xff1a; ①将图像展开为…