TypeScript核心语法进阶 —— 函数与对象类型
2026/7/14 19:08:24 网站建设 项目流程

阅读本文你能学到什么?

  • 如何为函数的参数和返回值添加类型
  • 可选参数、默认参数和 void 类型的用法
  • 接口(interface)的定义与使用
  • type 注解对象及与 interface 的区别

前言

在第二篇里,我们搞定了类型注解的基础,比如变量、数组这些。不过实际写项目的时候,函数和对象才是每天打交道最多的。

如果类型注解是基本功,那今天要讲的函数和对象类型定义,就算是真正的实战技能了。这篇文章不长,但会把关键点都拎出来,争取看完就能用上。

一、函数类型注解

函数类型是指给函数添加类型注解,本质上就是给函数的参数返回值添加类型约束

1.1 参数与返回值类型注解

语法:在参数后面加: 类型,在函数括号后面加: 返回值类型

// 基础用法:参数和返回值都指定类型functiongreet(name:string):string{return`Hello,${name}`}// 多个参数functionadd(a:number,b:number):number{returna+b}// 箭头函数写法constmultiply=(a:number,b:number):number=>a*b// 调用greet('Jack')// ✅greet(123)// ❌ 报错:类型"number"不能赋值给类型"string"add(1,'2')// ❌ 报错:类型"string"不能赋值给类型"number"

函数注解的好处:

  1. 避免因参数不对导致的函数内部逻辑错误—— 调用时必须传入正确类型的参数

  2. 对函数起到说明的作用—— 看类型签名就知道函数怎么用

1.2 函数表达式(箭头函数)

函数表达式的类型注解有两种方式:

方式一:参数和返回值分开注解

constadd=(a:number,b:number):number=>a+b

方式二:函数整体注解(只针对于函数表达式)

// 先看直接写法constadd:(a:number,b:number)=>number=(a,b)=>a+b// 更推荐:把类型提取出来,可以复用typecalcType=(a:number,b:number)=>numberconstadd:calcType=(a,b)=>a+bconstsub:calcType=(a,b)=>a-bconstmult:calcType=(a,b)=>a*bconstdiv:calcType=(a,b)=>a/b

方式二适合函数类型较复杂或需要复用的场景。

1.3 可选参数

可选参数表示当前参数可传可不传,一旦传递实参必须保证参数类型正确。可选参数必须放在必选参数的后面

// lastName 是可选的,不传也可以functiongetFullName(firstName:string,lastName?:string):string{if(lastName){return`${firstName}${lastName}`}returnfirstName}getFullName('Jack')// ✅ 输出:JackgetFullName('Jack','Ma')// ✅ 输出:Jack Ma

1.4 默认参数

给参数赋默认值后,调用时如果不传该参数,会自动使用默认值。

functiongreet(name:string,title:string='先生'):string{return`您好,${title}${name}`}greet('张三')// ✅ 输出:您好,先生 张三greet('张三','女士')// ✅ 输出:您好,女士 张三

💡 小贴士:有默认值的参数也建议放在参数列表的末尾,让必填参数靠前,提高可读性。

1.5 无返回值 —— void

JS 中的有些函数只有功能没有返回值,此时使用void进行返回值注解,明确表示函数没有返回值。

// 只做操作,不返回数据functionlogMessage(msg:string):void{console.log(msg)}// 或者 return; 不返回值functionlogAndReturn(msg:string):void{console.log(msg)return// 不返回任何值}

注意事项:在 JS 中如果没有返回值,默认返回的是undefined。但在 TS 中voidundefined不是一回事,undefined在 TS 中是一种明确的简单类型。如果指定返回值为undefined,那返回值必须是undefined类型。

二、对象类型注解 —— 接口(interface)

在 TS 中使用interface(接口)来描述对象数据的类型,常用于给对象的属性和方法添加类型约束。

2.1 基础用法

// 定义接口interfaceUser{name:stringage:number}// 使用接口约束对象letuser:User={name:'Jack',age:18}// ❌ 属性不能多也不能少letuser2:User={name:'Jack'// 缺少 age,报错!}letuser3:User={name:'Jack',age:18,gender:'male'// ❌ 多了一个 gender,报错!}

接口就像一份“契约”,规定了对象必须有哪些属性、每个属性是什么类型,属性不能多也不能少。

2.2 接口的典型场景

在常规业务开发中,接口最典型的场景就是前后端数据通信

  1. 前端向后端发送数据:收集表单对象数据时的类型校验

  2. 前端使用后端数据:渲染后端对象数组列表时的智能提示

// 模拟后端返回的用户数据interfaceUser{id:numbername:stringage:numberaddress:string}// 后端返回的用户列表constuserList:User[]=[{id:1,name:'张三',age:20,address:'北京市朝阳区'},{id:2,name:'李四',age:22,address:'上海市浦东新区'}]// 遍历渲染时,编辑器会有完整的智能提示userList.forEach(item=>{console.log(item.name)// ✅ 自动提示 nameconsole.log(item.address)// ✅ 自动提示 address})

输入 item. 时,编辑器会自动提示接口中定义的所有属性及其类型,如上图所示。

💡 给新手的提醒:上面的例子是理想化的写法。 实际项目中,接口字段可能很多,前端只定义用到的核心字段即可。非核心字段先用anyRecord<string, any>过渡,后续再逐步完善。

2.3 可选属性和只读属性

修饰符写法作用
可选属性属性名?: 类型可以有,也可以没有
只读属性readonly 属性名: 类型只能在创建时赋值,之后不能修改
interfaceUser{readonlyid:number// 只读:创建后不能改name:stringage:numberemail?:string// 可选:可以有也可以没有}letuser:User={id:1001,name:'Jack',age:18// email 不写也可以}user.email='jack@example.com'// ✅ 可选属性可以后赋值// user.id = 1002 // ❌ 报错:只读属性不能修改

readonly 常用于 ID、创建时间等一旦生成就不应该改变的字段,能在编译阶段防止误修改。

2.4 接口的继承

接口的很多属性是可以进行类型复用的,使用extends实现接口继承。

// 基础接口interfacePerson{name:stringage:number}// 继承 Person,新增 grade 属性interfaceStudentextendsPerson{grade:number}letstu:Student={name:'小明',age:18,grade:3// ✅ 必须有}

接口还可以同时继承多个接口

interfaceTimestamp{createdAt:Date updatedAt:Date}interfacePerson{name:stringage:number}// User 同时继承 Person 和 TimestampinterfaceUserextendsPerson,Timestamp{email:string}constuser:User={name:'Jack',age:18,email:'jack@example.com',createdAt:newDate(),updatedAt:newDate()}

三、type 注解对象

在第二篇中,我们用type定义了联合类型。其实type也可以用来定义对象结构,作用和interface类似。

// 使用 type 注解对象typeUser={name:stringage:numberemail?:string}letuser:User={name:'Jack',age:18}

type + 交叉类型模拟继承

类型别名配合交叉类型(&)可以模拟继承,同样可以实现类型复用。

// 基础类型typePerson={name:stringage:number}// 使用交叉类型模拟继承typeStudent=Person&{grade:number}letstu:Student={name:'小明',age:18,grade:3}

四、interface 对比 type —— 到底用哪个?

在实际开发中,很多场景下interfacetype都可以使用,那到底该选哪个?

4.1 相同点

① 都能描述对象类型

// 用 interface 描述对象interfaceUserInterface{name:stringage:number}// 用 type 描述对象typeUserType={name:stringage:number}

② 都能实现继承(interface使用extendstype配合交叉类型&

// interface 用 extends 继承interfacePerson{name:string}interfaceStudentextendsPerson{grade:number}// type 用 & 交叉类型实现继承typePersonType={name:string}typeStudentType=PersonType&{grade:number}

4.2 不同点

特性interfacetype
描述对象✅ 可以✅ 可以
描述联合类型❌ 不可以✅ 可以
描述基本类型❌ 不可以✅ 可以
同名合并✅ 可以(属性取并集)❌ 不可以(会报错)
继承方式extends&(交叉类型)
// ✅ type 的独有能力:定义联合类型和基本类型别名typeID=string|numbertypeName=string// ❌ type 重复声明会报错typePoint={x:number}typePoint={y:number}// ❌ 报错:重复标识符// ✅ interface 可以重复声明,自动合并interfacePoint{x:number}interfacePoint{y:number}// 等价于 { x: number; y: number }

4.3 选择建议

关于interfacetype用哪个,社区有两个主流观点:

  • 新手入门阶段:先统一用type,它最灵活,一个语法管所有,不容易出错

  • 正式项目开发:两者配合使用——用 type 定义非对象类型(联合、元组、映射等),用interface定义需要被类实现或需要扩展到第三方库的对象契约

两者都能描述对象结构,但各有所长。核心原则是:用最能表达你意图的那个

五、开发中的常见错误与避坑指南

常见错误正确写法说明
function add(a, b): numberfunction add(a: number, b: number): number参数也要加类型,不能只给返回值加
function greet(name?: string, title: string)function greet(name: string, title?: string)可选参数必须在必选参数后面
接口属性少写或多写严格按照接口定义赋值属性不能多也不能少
混淆voidundefined无返回值用void,返回undefinedundefined它们是不同的类型

六、本篇小结

知识点示例说明
函数参数类型function fn(a: number)约束参数类型
函数返回值类型function fn(): string约束返回值类型
void类型function fn(): void {}无返回值的函数
可选参数function fn(a?: string)参数可传可不传,必须放在末尾
默认参数function fn(a: string = 'hi')不传参时使用默认值
接口定义对象interface User { name: string }约束对象的形状,属性不能多也不能少
接口可选属性age?: number属性可有可无
接口只读属性readonly id: number创建后不可修改
接口继承interface Student extends Person复用接口定义
接口多继承interface User extends Person, Timestamp同时继承多个接口
type注解对象type User = { name: string }interface作用相似
type交叉类型type Student = Person & { grade: number }模拟继承

核心记忆口诀

函数参数要注解,返回值也别忘。可选参数放末尾,接口对象最擅长。需要复用用继承,复杂联合用 type。

下篇预告

📖 上篇回顾:TypeScript 核心语法入门 —— 类型注解与类型组合

本篇我们学会了函数和对象的类型注解,下一篇将进入 TypeScript 的字面量类型和类型推论,掌握更精确的类型定义方式,让类型注解更加精准。

欢迎持续关注 🚀

参考资料

  • TypeScript 官方文档 —— Everyday Types
  • TypeScript 官方手册 —— 接口
  • TypeScript 官方文档 —— 函数类型

————
晓说前端 · 正在从“会写”到“搞懂”的路上
如果这篇文章帮到了你,点个关注,一起进阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询