TypeScript中的函数类型定义与类型约束

函数类型定义与类型约束


一、核心概念:类型别名与函数类型

1. 类型别名(Type Alias)
定义

类型别名使用 type 关键字为现有类型创建一个新名称,可以用于:

  • 基础类型(如 stringnumber);
  • 复杂类型(如函数类型、对象类型、联合类型、元组等)。
函数类型别名的语法
type FunctionTypeAlias = (param1: Type1, param2: Type2, ...): ReturnType => { ... };
作用
  • 类型复用:避免重复编写相同的类型表达式。
  • 可读性:通过有意义的名称(如 GreetFunction)提升代码可读性。
  • 类型约束:确保函数参数和返回值的类型符合预期。

二、示例代码详解

1. 类型别名定义函数类型
type GreetFunction = (a: string) => void;
关键点
  • 参数名称的必要性
    • 参数名 a 在类型定义中是必须的,但实际函数的参数名可以不同。
    • 如果省略参数名(如 (string) => void),TypeScript 会将其解释为:
      • 参数名为 string,类型为 any(因为未显式指定类型),导致类型错误。
  • 返回值类型 void
    • 表示函数无返回值,若函数尝试返回值,TypeScript 会报错。

2. 函数 greeter 的定义
function greeter(fn: GreetFunction) {fn("Hello");
}
关键点
  • 类型约束
    • fn 必须符合 GreetFunction 类型,即:
      • 接受一个 string 类型参数。
      • 无返回值。
  • 类型安全
    • 如果传入的函数不符合类型要求,TypeScript 会在编译阶段直接报错,避免运行时错误。

3. 函数调用示例
合法用例
// 合法:函数参数类型和返回值类型匹配
function print(s: string) {console.log(s);
}
greeter(print); // 合法
错误用例
// 错误 1:参数类型不匹配
greeter((num: number) => console.log(num)); // 报错!参数类型是 number,但需要 string// 错误 2:返回值类型不匹配
function greetWithReturn(s: string): string {return "Hello, " + s;
}
greeter(greetWithReturn); // 报错!返回值类型是 string,但需要 void

三、为什么需要这种写法?

优势
  1. 类型复用

    • 如果需要多次使用相同函数类型,只需引用类型别名:

      // 多次使用 GreetFunction 类型
      function anotherGreeter(fn1: GreetFunction, fn2: GreetFunction) {fn1("Hi");fn2("Hello");
      }
      
  2. 可读性

    • 类型别名(如 GreetFunction)比直接写 (a: string) => void 更直观,尤其在复杂类型中:

      // 复杂类型示例:带可选参数和默认值的函数类型
      type Logger = (message: string, level: string = "info") => void;
      
  3. 类型约束

    • 确保函数参数和返回值的类型安全,避免因类型不匹配导致的运行时错误。

四、对比直接使用函数类型表达式

直接定义函数类型
// 直接写函数类型表达式
function greeter(fn: (a: string) => void) {fn("Hello");
}
区别
特性类型别名直接类型表达式
可读性更清晰(如 GreetFunction 名称直观)复杂类型时代码冗长且难读
复用性可复用(在多个函数中引用)无法复用,需重复书写类型
维护性修改类型时只需改一处需修改所有使用该类型的函数
复杂类型支持联合类型、交叉类型等复杂场景仅适合简单类型定义

五、扩展:更复杂的函数类型

1. 带返回值的函数类型
// 定义带返回值的函数类型
type MathFunction = (a: number, b: number) => number;// 使用类型别名
function calculate(fn: MathFunction, a: number, b: number): number {return fn(a, b);
}// 调用示例
const sum = calculate((x, y) => x + y, 1, 2); // 合法,返回 3
2. 可选参数与默认值
// 定义可选参数和默认值的函数类型
type Logger = (message: string, level?: string) => void;// 使用类型别名
function log(fn: Logger) {fn("Error occurred"); // 合法,level 可选fn("Warning", "high"); // 合法,level 为 "high"
}// 合法函数实现
function consoleLog(message: string, level = "info") {console.log(`[${level}] ${message}`);
}
log(consoleLog); // 合法
3. 剩余参数(Rest Parameters)
// 定义接受任意数量参数的函数类型
type LoggerWithArgs = (...messages: string[]) => void;// 使用类型别名
function logAll(fn: LoggerWithArgs) {fn("Error", "Warning", "Info"); // 合法
}// 合法函数实现
function multiLog(...messages: string[]) {messages.forEach((msg) => console.log(msg));
}
logAll(multiLog); // 合法

六、与泛型结合:增强类型灵活性

1. 泛型函数类型
// 定义泛型函数类型:返回第一个参数
type FirstElement<T> = (arr: T[]) => T | undefined;// 使用类型别名
function getFirst<T>(fn: FirstElement<T>, arr: T[]): T | undefined {return fn(arr);
}// 调用示例
const numbers = [1, 2, 3];
const firstNumber = getFirst<number>(firstElement, numbers); // 类型是 number | undefined
2. 泛型约束
// 约束函数参数必须包含 length 属性
type HasLength = { length: number };
type GetLongest<T extends HasLength> = (a: T, b: T) => T;// 使用类型别名
function compareLength<T extends HasLength>(fn: GetLongest<T>, a: T, b: T): T {return fn(a, b);
}// 合法调用
const str1 = "apple";
const str2 = "banana";
const longestStr = compareLength<string>(longest, str1, str2); // 返回 "banana"

七、实际应用场景

1. 回调函数类型约束
// 定义回调函数类型:接收错误和数据
type Callback<T> = (err: Error | null, data: T | null) => void;// 使用类型别名
function fetchData<T>(url: string, callback: Callback<T>) {// 模拟异步请求callback(null, { data: "success" } as T);
}// 调用示例
fetchData<string>("https://api.example.com", (err, data) => {if (err) console.error(err);else console.log(data); // 类型是 string | null
});
2. 高阶函数(Higher-Order Functions)
// 定义高阶函数类型:接受函数并返回函数
type HigherOrderFunction = (fn: (a: number) => number) => (b: number) => number;// 使用类型别名
function createAdder(hof: HigherOrderFunction): (b: number) => number {return hof((a) => a + 1);
}// 合法实现
const adder = createAdder((fn) => (b) => fn(b) * 2);
console.log(adder(3)()); // 输出 8((3+1)*2)

八、总结

核心要点
  1. 类型别名
    • 通过 type 关键字定义可复用的函数类型,提升代码可读性和维护性。
    • 支持复杂类型(如泛型、联合类型、可选参数)。
  2. 函数类型约束
    • 确保函数参数和返回值的类型安全,避免运行时错误。
    • 适用于高阶函数、回调函数等复杂场景。
  3. 与泛型结合
    • 通过泛型增强类型灵活性,实现类型安全的通用函数。
适用场景
  • 高阶函数:需要传递函数作为参数或返回函数时。
  • API 回调:约束回调函数的参数和返回值类型。
  • 代码复用:在多个函数中复用相同的函数类型定义。

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

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

相关文章

相机DreamCamera2录像模式适配尺寸

在开发中遇到 一个问题&#xff0c;相机切换视频模式时&#xff0c;预览时&#xff0c;界面不能充满屏幕两侧有黑边&#xff0c;客户要求修改&#xff0c;在此记录 一问题现象&#xff1a; 系统相机在视频模式下预览时如下现象如图1&#xff0c;期望现象如图2: 图1 …

SpringCloud组件——Gateway

一.网关 1.问题提出 我们通过Eureka&#xff0c;Nacos解决了服务注册&#xff0c;服务发现的问题&#xff0c;使用SpringCloud LoadBalance解决了负载均衡的问题&#xff0c;使用OpenFeign解决了远程调用的问题。 但是当前所有微服务的接口都是直接对外暴露的&#xff0c;可…

C#中构造器及属性的加载顺序

一.基本原则: 先加载静态构造函数和静态字段,后加载普通构造函数和普通字段;先加载基类再加载子类; 二.具体的加载顺序: 父类静态字段--->父类静态构造函数--->子类静态字段--->子类静态构造函数--->父类实例字段---> 父类实例构造函数--->子类实例字段-…

Python面试问题

一、Python 基础 1. Python 的特点 动态类型&#xff1a;变量无需声明类型。解释型语言&#xff1a;逐行解释执行。支持多种编程范式&#xff08;面向对象、函数式、过程式&#xff09;。 2. 列表&#xff08;List&#xff09;与元组&#xff08;Tuple&#xff09;的区别 特…

计算机视觉进化论:YOLOv12、YOLOv11与Darknet系YOLOv7的微调实战对比

摘要 YOLO系列作为实时目标检测领域的重要里程碑&#xff0c;持续引领速度与精度的平衡发展。本文围绕YOLOv7&#xff08;基于Darknet框架&#xff09;、YOLOv11及YOLOv12&#xff0c;系统、深入地对比了三款模型的架构创新、微调策略、核心技术及应用场景。我们详细解析了三者…

SQL Server 存储过程开发规范

SQL Server 存储过程开发规范&#xff08;高级版&#xff09; 1. 总则 1.1 目标 本规范旨在&#xff1a; 提高存储过程的事务一致性、异常可追踪性、错误透明度。 统一日志记录、错误码管理、链路追踪&#xff08;Trace ID&#xff09;。 支持复杂事务场景&#xff08;嵌套…

opendds的配置

配置的使用 文档中说明有4种使用配置的方式&#xff1a; 环境变量 命令行参数&#xff08;将覆盖环境变量中的配置&#xff09; 配置文件&#xff08;不会覆盖环境变量或命令行参数中的配置&#xff09; 用户调用的 API&#xff08;将覆盖现有配置&#xff09; 这里对开发…

(Go Gin)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收

1. 路由 gin 框架中采用的路优酷是基于httprouter做的 HttpRouter 是一个高性能的 HTTP 请求路由器&#xff0c;适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用&#xff0c;特别适合需要高性能和简单路由的应用场景。 主要特点 显式匹配&#xff1a;与其他路由…

Marin说PCB之----板材的替换注意事项

由于最近很多武林上的主流门派都需要采用将的本方案&#xff0c;小编所在的宗门古族也是不例外了&#xff0c;宗门大长老韩立现在想把之前一直在用的板材EM370Z替换成生益的Autolad3&#xff0c;让我去拿资料分析一下是否可以替换。下图所示是就是小编我做的一个表格关于两家板…

4月28日信息差全景:国际局势、科技突破与市场震荡一、国际政治与安全:俄乌冲突关键转折

一、国际政治与安全:俄乌冲突关键转折 1. 乌克兰反攻进展与情报差异 前线动态: 俄国防部称在顿涅茨克击退乌军三次进攻,摧毁12辆坦克;乌方则宣布在巴赫穆特南部推进2公里,双方战报存在显著差异。 信息差根源:战场信息管控导致西方媒体与俄媒报道截然不同。 国际援助: 美…

关系数据的可视化

目录 【实验目的】 【实验原理】 【实验环境】 【实验步骤】 一、安装Python所需要的第三方模块 二、实验 【实验总结】 【实验目的】 1.掌握关系数据在大数据中的应用 2.掌握关系数据可视化方法 3. python 程序实现图表 【实验原理】 在传统的观念里面&#xff0…

夏季道路安全的AI革命:节省人力、提升效率

AI夏季道路安全&#xff1a;用智能算法守护每一条街道 背景&#xff1a;夏季道路安全的挑战与机遇 夏季是道路安全事件的高发期。高温天气容易导致驾驶员疲劳、行人行为异常&#xff08;如跌倒或中暑&#xff09;&#xff0c;同时&#xff0c;车流量增加、夜间活动频繁…

HTML标记语言_@拉钩教育【笔记】

目录 1.文本标签 2.格式化标签 3.图片标签 4.超链接标签 5.表格标签 6表单标签 6.1 6.2 6.3 7.行内框架(超链接内套一个页面) 8.多媒体标签(音/视频) 1.文本标签 2.格式化标签 3.图片标签 4.超链接标签 5.表格标签 6表单标签 6.1 6.2 6.3 7.行内框架(超链接内套一个…

Python 中调用方法内部定义的类详解(类在方法中的各种操作)

更多内容请见: python3案例和总结-专栏介绍和目录 文章目录 一、基本概念1.1 方法内部定义类概述1.2 方法内部定义类的特点1.3 替代方案二、基本使用2.1 直接在方法内部使用2.2 返回类定义供外部使用2.3 返回类的实例2.4 作为闭包使用(访问外部变量)三、高级用法3.1 动态类创…

第36课 常用快捷操作——用“鼠标右键”退出当前命令

概述 在AD 20软件中&#xff0c;很多的命令都是可以一直连续下去的&#xff0c;比方说放置一个元器件符号&#xff0c;如果你当中不取消的话&#xff0c;那就可以一直执行下去&#xff0c;放完一个接着放下一个&#xff0c;放完一个接着放下一个…… 想要退出这种连续进行的命…

FFTW3.3.10库与QT结合的使用

FFTW&#xff08;Fastest Fourier Transform in the West&#xff09;是世界上最快的FFT&#xff0c; 实测计算长度为10000的double数组&#xff0c; 单次运行时间在2ms左右。为了详细了解FFTW以及为编程方便&#xff0c;特将用户手册看了一下&#xff0c;并结合手册制作了以下…

服务器异地备份,服务器异地备份有哪些方法?

服务器异地备份是应对区域性灾难&#xff08;如地震、火灾、洪水&#xff09;或人为事故&#xff08;如误删除、勒索病毒攻击&#xff09;的关键策略&#xff0c;其核心在于将数据副本存储在物理隔离的地理位置&#xff0c;确保主数据中心故障时仍可恢复业务。 以下是主流的异地…

导轨表面硬化处理有哪些?

导轨是机器工作的重要组成部分&#xff0c;它与滑块紧密配合&#xff0c;保证机器的运转精度和定位精度。为了提高导轨的耐磨性能和使用寿命&#xff0c;通常在导轨表面加工硬化层。硬化层一般是在导轨表面形成一层高硬度和高强度的薄层&#xff0c;有效地提高了导轨的耐磨性能…

Android Compose vs 传统View系统:全面对比与选型指南

Android Compose vs 传统View系统&#xff1a;全面对比与选型指南 一、引言 随着Android Jetpack Compose的正式发布&#xff0c;Android开发迎来了全新的声明式UI框架。本文将全面对比Compose与传统View系统的差异&#xff0c;帮助开发者做出合理的技术选型。 二、核心架构…

C#中实现JSON解析器

JSON(JavaScript Object Notation)即 JavaScript 对象表示法,是一种轻量级的数据交换格式。 起源与发展 JSON 源于 JavaScript 编程语言,是 JavaScript 对象字面量语法的一个子集。但如今它已经独立于 JavaScript,成为一种通用的数据格式,广泛应用于各种编程语言和系统…