当前位置: 首页 > news >正文

阮一峰《TypeScript 教程》学习笔记——类型系统

1. 一段话总结

TypeScript 函数类型需明确参数类型返回值类型(返回值类型可省略,TS 自动推断),变量赋值函数时有两种类型写法(推断式、显式箭头式),且支持用 type/interface 定义类型别名;存在Function 类型(无约束,不推荐)与箭头函数类型(写法与普通函数类似,需注意参数圆括号);参数支持可选参数(尾部可加 ?)、默认值(与可选不可共存)、解构(需显式声明解构类型)、rest 参数(数组/元组类型,可嵌套)、只读参数(readonly 修饰,禁止内部修改);返回值类型有void(正常无返回,允许 undefined/nullnever(函数不正常结束,如抛错/死循环);函数内部可声明局部类型(仅内部有效),支持高阶函数(返回值为函数)函数重载(多类型声明+单一实现,需按精度排序),还可通过 new 关键字声明构造函数类型(用于类或构造函数参数)。


2. 思维导图

在这里插入图片描述


3. 详细总结

一、函数类型基础声明

TypeScript 函数需明确参数类型返回值类型,核心规则与写法如下:

1. 基本写法
  • 函数声明时,参数类型写在参数名后,返回值类型写在参数列表圆括号后(返回值可省略,TS 自动推断):
    function hello(txt:string):void { console.log('hello ' + txt); } // 显式返回值类型
    function hello(txt:string) { console.log('hello ' + txt); } // 省略返回值类型(TS 推断为 void)
    
  • 变量赋值函数的两种类型写法:
写法类型语法格式示例注意事项
推断式const 变量 = function(参数:类型) { ... }const hello = function(txt:string) { console.log(txt); }依赖右侧函数自动推断变量类型
显式箭头式const 变量: (参数:类型)=>返回值类型 = function(参数) { ... }const hello: (txt:string)=>void = function(txt) { console.log(txt); }1. 参数必须加圆括号;2. 参数名必写(否则视为“参数名=string,类型=any”);3. 变量类型与函数参数名可不同
2. 类型别名与接口声明
  • type 定义函数类型别名(推荐,简化重复类型):
    type MyFunc = (txt:string)=>void;
    const hello:MyFunc = function(txt) { console.log(txt); };
    
  • interface 定义函数类型(对象写法翻版,适用于函数带属性的场景):
    interface MyFunc { (a:number, b:number):number; }
    const add:MyFunc = (a,b)=>a+b;
    
3. Function 类型
  • 表示“任意函数”,参数与返回值均为 any(无约束,不推荐):
    function doSomething(f:Function) { return f(1,2,3); } // f 可接受任意参数,返回任意值
    

二、箭头函数类型

  • 类型写法与普通函数类似:参数类型写在参数后,返回值类型写在参数圆括号后:
    const repeat = (str:string, times:number):string => str.repeat(times);
    
  • 与“函数类型的箭头表示”区分:前者是“箭头函数的类型声明”,后者是“函数类型的简写”(如参数类型):
    // 函数类型的箭头表示(参数 fn 的类型)
    function greet(fn:(a:string)=>void):void { fn('world'); }
    

三、参数类型细节

1. 可选参数
  • 语法:参数名后加 ?,表示“参数可省略,类型为‘原始类型|undefined’”:
    function f(x?:number) { return x; }
    f(); // 正确;f(undefined); // 正确
    
  • 限制:可选参数只能在参数列表尾部(不能在可选参数后加必填参数),否则报错:
    let myFunc: (a?:number, b:number)=>number; // 报错(可选参数在必填前)
    
2. 参数默认值
  • 与 JavaScript 语法一致,默认值参数自动为“可选”,不能与 ? 同时使用(否则报错):
    function createPoint(x:number=0, y:number=0):[number,number] { return [x,y]; }
    createPoint(); // [0,0](正确)
    function f(x?:number=0) { ... } // 报错(可选与默认共存)
    
  • 非尾部默认值:调用时不能省略,需显式传入 undefined 触发默认值:
    function add(x:number=0, y:number) { return x+y; }
    add(undefined, 1); // 1(正确);add(1); // 报错(y 未传)
    
3. 参数解构
  • 需显式声明解构对象/数组的类型,可结合 type 简化:
    // 解构数组
    function f([x,y]:[number,number]) { ... }
    // 解构对象(原始写法)
    function sum({a,b,c}:{a:number; b:number; c:number}) { console.log(a+b+c); }
    // 解构对象(结合 type 简化)
    type ABC = {a:number; b:number; c:number};
    function sum({a,b,c}:ABC) { console.log(a+b+c); }
    
4. rest 参数
  • 表示“剩余所有参数”,支持数组(成员类型相同)或元组(成员类型不同),可嵌套/结合解构:
    // 数组类型 rest 参数
    function joinNumbers(...nums:number[]) { ... }
    // 元组类型 rest 参数(支持可选成员)
    function f(...args:[boolean, string?]) { ... }
    // 嵌套 rest 参数
    function f(...args:[boolean, ...string[]]) { ... }
    // 结合解构的 rest 参数
    function repeat(...[str, times]:[string, number]):string { return str.repeat(times); }
    
5. 只读参数
  • readonly 修饰参数类型(仅支持数组/对象类型),禁止函数内部修改参数:
    function arraySum(arr:readonly number[]) {arr[0] = 0; // 报错(只读参数禁止修改)
    }
    

四、返回值类型(void vs never)

两种核心返回值类型的区别如下:

类型核心含义适用场景允许返回值与 JS 对应逻辑
void函数正常执行结束,无返回值仅执行副作用(如 console.log)1. 无 return;2. return undefined;3. return null(strictNullChecks 关闭时)函数默认返回 undefined
never函数不正常执行结束(无返回过程)1. 抛错函数;2. 死循环函数无(函数无法执行到 return)函数执行中断(抛错)或无限执行
  • 示例:
    // void 类型(正常无返回)
    function f():void { console.log('hello'); }
    // never 类型(抛错函数)
    function fail(msg:string):never { throw new Error(msg); }
    // never 类型(死循环函数)
    const sing:()=>never = () => { while(true) { console.log('sing'); } };
    

五、其他重要特性

1. 局部类型
  • 函数内部声明的类型(仅在函数内部有效,外部使用报错):
    function hello(txt:string) {type Message = string; // 局部类型let newTxt:Message = 'hello ' + txt;return newTxt;
    }
    const newTxt:Message = hello('world'); // 报错(Message 外部不可见)
    
2. 高阶函数
  • 定义:返回值为函数的函数(即“函数返回函数”):
    const multiply = (x:number) => (y:number) => x*y; // 高阶函数
    const double = multiply(2);
    double(3); // 6
    
3. 函数重载
  • 定义:函数可接受“不同类型/个数的参数”,执行不同逻辑(多类型声明+单一实现)。
  • 核心规则:
    1. 先写“精度高”的类型声明(如具体类型),再写“精度低”的(如联合类型),按顺序检查;
    2. 最后一个“实现函数”的类型需兼容所有声明类型;
    3. 实现内部需通过判断(如 typeof/Array.isArray)处理不同参数场景。
  • 示例:
    // 重载声明(精度从高到低)
    function reverse(str:string):string;
    function reverse(arr:any[]):any[];
    // 实现函数(兼容所有声明)
    function reverse(stringOrArray:string|any[]):string|any[] {if (typeof stringOrArray === 'string') {return stringOrArray.split('').reverse().join('');} else {return stringOrArray.slice().reverse();}
    }
    
  • 替代方案:简单场景优先用联合类型替代重载(简化代码):
    // 联合类型替代重载
    function len(x:string|any[]):number { return x.length; }
    
4. 构造函数类型
  • 定义:用 new 关键字声明“需通过 new 调用的构造函数”类型,适用于类或构造函数参数:
    // 类定义
    class Animal { numLegs:number = 4; }
    // 构造函数类型
    type AnimalConstructor = new () => Animal;
    // 接受构造函数的函数
    function create(c:AnimalConstructor):Animal { return new c(); }
    // 调用(类本质是构造函数)
    const a = create(Animal);
    
  • 双用途类型(支持“普通函数+构造函数”):用对象写法声明:
    type F = {new (s:string):object; // 构造函数类型(n?:number):number;    // 普通函数类型
    };
    

4. 关键问题

问题1:TypeScript 中变量赋值函数时,“推断式写法”与“显式箭头式写法”的核心差异是什么?在什么场景下推荐用显式写法?

答案
核心差异在于“类型是否显式声明”:

  • 推断式写法(如 const hello = function(txt:string) { ... }):依赖右侧函数的参数/返回值类型,自动推断变量 hello 的类型,无需手动写类型,简洁高效;
  • 显式箭头式写法(如 const hello: (txt:string)=>void = function(txt) { ... }):需手动用“(参数:类型)=>返回值类型”声明变量类型,右侧函数参数类型可省略(TS 自动匹配变量类型)。

推荐显式写法的场景:

  1. 多人协作项目(显式类型提升代码可读性,明确函数输入输出约束);
  2. 函数类型复杂或需复用(如后续需将相同类型赋值给其他变量,可结合 type 定义别名);
  3. 防止后续代码意外修改函数类型(如避免误加不兼容的参数/返回值)。

问题2:TypeScript 中 void 类型与 never 类型都“无返回值”,如何精准区分两者的适用场景?结合示例说明。

答案
两者的核心区分点是“函数是否正常执行结束”,适用场景完全不同:

  1. void 类型:适用于“函数正常执行结束,但无有意义返回值”的场景(仅执行副作用,如打印、修改外部变量),函数有完整的“执行-结束”流程,允许返回 undefinednullstrictNullChecks 开启时仅允许 undefined);
    示例:function logMsg(msg:string):void { console.log(msg); }(函数正常打印后结束,无返回值)。

  2. never 类型:适用于“函数无法正常执行结束”的场景(无“执行-结束”流程),函数要么抛错中断执行,要么陷入死循环无限执行,不可能有任何返回值
    示例1(抛错):function throwError(msg:string):never { throw new Error(msg); }(抛错后函数立即中断,无返回过程);
    示例2(死循环):function infiniteLoop():never { while(true) { console.log('loop'); } }(函数永远执行,无法结束)。

简言之:void 是“有结束,无返回值”,never 是“无结束,无返回过程”。

问题3:函数重载中,“重载声明的排序”与“实现函数的类型兼容性”为何是关键?如果排序错误或实现类型不兼容,会导致什么问题?

答案
函数重载的核心逻辑是“按声明顺序匹配参数类型,找到第一个匹配项后停止检查”,且“实现函数需覆盖所有声明场景”,因此排序与兼容性至关重要:

  1. 重载声明排序的关键原因
    TypeScript 按“声明顺序从先到后”检查参数类型,若“精度低”的声明(如联合类型、any)排在前面,会优先匹配所有调用,导致“精度高”的声明(如具体类型)永远无法被匹配,失去重载意义。
    反例:

    function f(x:any):number; // 精度低的声明在前
    function f(x:string):0|1; // 精度高的声明在后(永远无法匹配)
    function f(x:any):any { return x.length; }
    const a:0|1 = f('hi'); // 报错(f('hi') 匹配第一个声明,返回类型为 number,与 0|1 不兼容)
    
  2. 实现函数类型兼容性的关键原因
    实现函数是重载的“唯一执行逻辑”,其参数/返回值类型必须能覆盖所有声明类型,否则会出现“声明支持的场景,实现无法处理”的矛盾,导致调用报错。
    反例:

    function fn(x:boolean):void; // 声明1:参数为 boolean
    function fn(x:string):void;  // 声明2:参数为 string
    function fn(x:number|string) { ... } // 实现参数类型为 number|string(不兼容声明1的 boolean)
    fn(true); // 报错(实现无法处理 boolean 类型参数,与声明1冲突)
    

若排序错误,会导致“重载声明失效”;若实现类型不兼容,会导致“部分声明场景无法调用”,两者均会破坏重载的设计目的。

http://www.dtcms.com/a/521544.html

相关文章:

  • 网站如何做微信支付宝支付湖南网站排名优化公司
  • 房产网站推广做自己移动端网站
  • 江阴网站建设公司vs用户登录注册网站建设代码
  • 锁和原子变量的基础介绍
  • asp网站开发实训报告公司中英文网站建设
  • 状态机之tinyfsm
  • Spring中@Configuration注解的proxyBeanMethods属性详解
  • RSI超买信号与仓位递减结合的ETF止盈策略实现与验证
  • 浙江企业网站建设上海cms建站系统
  • 太原做app网站建设上海网站建设seo公司哪家好
  • windows 安装 nginx
  • 十六、Linux网络配置
  • wordpress多站点支付插件企业网页建设公司咨询电话
  • Linux安装nvm教程(脚本与解压缩两种方式)
  • 无锡网站制作哪家便宜遵义网站建设制作公司
  • 制作网站流程湖南易图科技发展有限公司
  • 1.1、开篇:AI如何重塑网络安全攻防格局?
  • 福州 哈尔滨网站建设 网络服务连云港市网站建设
  • 电商智能客服机器人:客服的服务革新之路
  • 网站建设及推广方案桂林两江四湖象山景区简介
  • (3)Kafka生产者分区策略、ISR、ACK、一致性语义
  • 做盗链网站上国外网站用什么dns
  • 平面设计创意网站建设嵌入式软件开发招聘
  • TraceId如何在Spring-Cloud微服务的REST调用中传递
  • 网站关键词符号怎么样提高网站点击率
  • 【经典书籍】《编写可读代码的艺术》精华
  • 网站推广专业术语代表性设计制作作品图片
  • 小游戏网站欣赏wordpress 在线报名系统
  • 传奇手游大型网站seo计费怎么刷关键词的
  • 启东网站建设什么是网络营销竞争的利器之一