TypeScript 基础入门:对象、函数、数组、元组、枚举和类型别名
摘要
上一篇记录了 TypeScript 中的基础类型,比如字面量类型、联合类型、any、unknown、void 和 never。这篇继续记录 TypeScript 中更常用的一些类型写法,主要包括对象类型、可选属性、任意属性、函数类型、数组类型、元组类型、枚举类型和类型别名。
本文代码来自 Vue/uni-app 项目中的 .vue 文件,使用的是 Vue 3 的 <script setup lang="ts"> 写法。
一、在 Vue 文件中使用 TypeScript
在 Vue 单文件组件中使用 TypeScript,需要给 script 标签添加 lang="ts":
<script setup lang="ts">
// TypeScript 代码
</script>
如果是在 Vue 3 项目中,还可以配合 script setup 语法,让代码更简洁。
二、object 类型
object 类型表示非原始类型,也就是对象、数组、函数等。
let a: object
它可以接收对象类型的值:
a = {}
a = []
a = function () {}
但是实际开发中,一般不推荐直接使用 object 来描述普通对象。因为 object 只表示“这是一个非原始值”,并不会告诉 TypeScript 这个对象里有哪些属性。
例如:
let user: object = {
name: 'ts',
age: 18
}
// user.name // 报错
虽然 user 里面确实有 name,但 TypeScript 只知道它是一个 object,不知道它具体有什么属性。
所以如果要描述对象结构,更推荐使用对象类型。
三、对象类型
对象类型可以明确规定对象中有哪些属性,以及这些属性分别是什么类型。
let b: { name: string; age: number; sex?: string }
这段代码表示:
name是必填属性,类型是stringage是必填属性,类型是numbersex是可选属性,类型是string
正确写法:
b = { name: 'ts', age: 18 }
b = { name: 'ts', age: 18, sex: 'male' }
错误写法:
// b = { name: 'ts' } // 报错,缺少 age 属性
对象类型的好处是可以让数据结构更清楚,也能在写代码时提前发现字段缺失或类型错误。
四、可选属性
可选属性使用 ? 表示。
let user: { name: string; age: number; sex?: string }
这里的 sex?: string 表示 sex 可以有,也可以没有。
user = { name: '张三', age: 18 }
user = { name: '张三', age: 18, sex: 'male' }
可选属性适合用在一些不一定存在的数据上,比如用户头像、备注、描述、标签等。
let article: {
title: string
content: string
description?: string
}
五、任意属性
如果一个对象除了固定属性外,还允许出现其他属性,可以使用索引签名。
let c: { name: string; [propName: string]: any }
这段代码表示:
name属性必须存在,并且类型是string- 其他属性可以有,也可以没有
- 其他属性名必须是字符串类型
- 其他属性的值可以是任意类型
示例:
c = { name: 'ts' }
c = { name: 'ts', age: 18 }
c = { name: 'ts', age: 18, isStudy: true }
这里的 [propName: string]: any 就是索引签名。
不过要注意,any 会降低类型安全。如果可以提前确定其他属性的类型,最好不要直接写 any。
例如:
let scoreMap: { [key: string]: number }
scoreMap = {
math: 90,
english: 95
}
这样表示对象中的每个属性值都必须是 number。
六、函数类型
函数类型可以规定参数类型和返回值类型。
let d: (a: number, b: number) => number
这表示 d 是一个函数:
- 第一个参数是
number - 第二个参数是
number - 返回值也是
number
赋值时需要满足这个函数类型:
d = function (a: number, b: number): number {
return a + b
}
也可以写成箭头函数:
d = (a: number, b: number): number => {
return a + b
}
如果参数类型或返回值类型不符合,就会报错。
// d = function (a: string, b: string): string {
// return a + b
// }
七、数组类型
TypeScript 中定义数组类型常见有两种写法。
第一种:类型[]
let e: string[]
e = ['ts', 'vue']
这表示数组中的每一项都必须是 string。
// e = ['ts', 123] // 报错
第二种:Array<类型>
let f: Array<number>
f = [1, 2, 3]
这表示数组中的每一项都必须是 number。
// f = [1, 2, '3'] // 报错
两种写法本质上都可以,日常开发中更常见的是:
let list: string[]
如果类型比较复杂,也可以使用泛型写法:
let users: Array<{ name: string; age: number }>
八、元组类型
元组类型可以理解为“固定长度和固定类型顺序的数组”。
let g: [string, string]
g = ['ts', 'vue']
这里的 g 必须是一个长度为 2 的数组,并且两个元素都必须是字符串。
// g = ['ts'] // 报错,长度不够
// g = ['ts', 18] // 报错,第二个元素必须是 string
再看另一个例子:
let h: [string, number]
h = ['ts', 18]
这里的 h 必须包含两个元素:
- 第一个元素是
string - 第二个元素是
number
元组常用于表示结构固定的数据,例如坐标、表格行、固定格式的返回值等。
let point: [number, number]
point = [120, 30]
九、枚举类型
枚举使用 enum 定义,适合表示一组有名字的常量。
enum Color {
Red,
Green,
Blue
}
默认情况下,枚举成员会从 0 开始自动编号:
Color.Red // 0
Color.Green // 1
Color.Blue // 2
可以使用枚举类型来限制变量的取值范围。
let i: Color
i = Color.Red
i = Color.Green
i = Color.Blue
这样 i 的值就只能来自 Color 这个枚举。
枚举也可以和对象类型一起使用:
let obj: { name: string; color: Color } = {
name: 'ts',
color: Color.Red
}
这表示 obj 必须包含:
name属性,类型是stringcolor属性,类型是Color
如果写成其他不属于 Color 的值,就会报错。
十、手动指定枚举值
枚举也可以手动指定值。
enum Direction {
Up = 1,
Down = 2,
Left = 3,
Right = 4
}
也可以使用字符串枚举:
enum RequestStatus {
Loading = 'loading',
Success = 'success',
Error = 'error'
}
字符串枚举在业务代码中更直观,因为打印出来的值更容易理解。
let status: RequestStatus = RequestStatus.Success
十一、类型别名 type
type 可以用来给一个类型起名字,这个名字就叫类型别名。
type Person = 1 | 2 | 3 | 4
上面代码表示 Person 这个类型只能是 1、2、3、4 中的一个值。
let j: Person
j = 1
// j = 'hello' // 报错
这里的 j 类型是 Person,所以只能赋值为数字字面量 1、2、3 或 4。
如果赋值字符串,就会报错:
// j = 'hello'
需要注意,type Person = 1 | 2 | 3 | 4 这里只是一个学习示例。实际开发中,类型别名通常会用来描述更有业务意义的类型。
例如请求状态:
type RequestStatus = 'loading' | 'success' | 'error'
let status: RequestStatus
status = 'loading'
status = 'success'
// status = 'done' // 报错
也可以用来描述对象结构:
type User = {
name: string
age: number
sex?: string
}
let user: User = {
name: 'ts',
age: 18
}
类型别名的好处是可以让复杂类型变得更清楚,也方便重复使用。
十二、本文完整练习代码
<template>
<view class="content"></view>
</template>
<script setup lang="ts">
// object 类型:表示非原始类型的值
let a: object
// 对象类型:必须包含 name 和 age,sex 是可选属性
let b: { name: string; age: number; sex?: string }
// b = { name: 'ts' } // 报错,缺少 age 属性
b = { name: 'ts', age: 18 }
b = { name: 'ts', age: 18, sex: 'male' }
// 索引签名:必须有 name 属性,其他属性可以有也可以没有
let c: { name: string; [propName: string]: any }
c = { name: 'ts' }
c = { name: 'ts', age: 18 }
// 函数类型
let d: (a: number, b: number) => number
d = function (a: number, b: number): number {
return a + b
}
// 数组类型
let e: string[]
e = ['ts', 'vue']
let f: Array<number>
f = [1, 2, 3]
// 元组类型
let g: [string, string]
g = ['ts', 'vue']
let h: [string, number]
h = ['ts', 18]
// 枚举类型
enum Color {
Red,
Green,
Blue
}
let i: Color
i = Color.Red
i = Color.Green
i = Color.Blue
let obj: { name: string; color: Color } = {
name: 'ts',
color: Color.Red
}
// 类型别名
type Person = 1 | 2 | 3 | 4
let j: Person
j = 1
// j = 'hello' // 报错,j 的类型是 Person,不能赋值为字符串
</script>
<style></style>
注意:如果想在项目中正常运行,演示“报错”的代码建议用注释保留,例如 // j = 'hello'。如果不注释,TypeScript 会真的提示类型错误。
十三、学习小结
本文主要记录了 TypeScript 中几种常见类型:
object:表示非原始类型,但不能描述具体属性- 对象类型:可以约束对象必须有哪些属性
- 可选属性:使用
?表示属性可有可无 - 索引签名:允许对象拥有额外属性
- 函数类型:限制函数参数和返回值
- 数组类型:限制数组中元素的类型
- 元组类型:限制数组的长度和每个位置的类型
- 枚举类型:表示一组有名字的常量
- 类型别名:使用
type给复杂类型起一个名字
学习 TypeScript 时,不要只记语法,更重要的是理解它在帮我们约束什么。类型写得越清楚,后期代码维护起来就越轻松。
更多推荐
所有评论(0)