遍历 Object 对象
interface IPerson{
name: string,
age: number,
hobbies: string[]
}
const p: IPerson = {
name: 'zs',
age: 12,
hobbies: ['reading', 'shopping']
}
对于实例 p 循环遍历的三种方式:
方式一:Object.keys 方式
type pKeys = keyof IPerson
const keys = Object.keys(p) as pKeys[]
keys.forEach((key)=>{
console.log(key, p[key])
})
方式二:for in
type pKeys = keyof IPerson
let key: pKeys
for(key in p){
console.log(key, p[key])
}
方式三:Object.entries
for(const[k, v] of Object.entries(p)){
console.log(k, v)
}
注意:这种方式获取的对象值 v 是 any 类型,使用时需要注意类型判断。
枚举类型取值
后端一般会给我们如下的枚举类型:
enum EnumScheduleType {
WORK_SCHEDULE = '工作班次',
REST_SCHEDULE = '休息班次',
}
在我们得到的数据可能直接是 scheduleType 为 WORK_SCHEDULE 或者 REST_SCHEDULE,这就需要将这些枚举转为用户能看懂的文字信息。如果我们直接通过 EnumScheduleType[scheduleType] 的方式获取对应的文字信息的话,编译器会告诉我们如下的错误:
意思就是不能随便使用 string 类型去匹配 EnumScheduleType 的值,正确如下:
// 定义 EnumScheduleType key 的范围
type ScheduleTypeStrings = keyof typeof EnumScheduleType
// 等价于
// type ScheduleTypeStrings = 'WORK_SCHEDULE' | 'REST_SCHEDULE';
// 后端获取数据,准确定义好其类型
const scheduleType: ScheduleTypeStrings = getFromServer()
// 获取值
const scheduleName = EnumScheduleType[scheduleType]
Vue 中 ref 组件类型 (InstanceType)
组件 HelloWorld.vue
// HelloWorld.vue
<template>
<p>{{msg}}</p>
</template>
<script lang="ts">
export default {
props: {
msg: String
},
setup(props: any) {
const print = ()=>{
console.log(props.msg)
}
return{
print
}
}
}
</script>
ref 使用该组件:使用 InstanceType 定义组件 HelloWorld.vue 的类型
// App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld
ref="helloRef"
msg="Welcome to Your Vue.js + TypeScript App"
/>
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
import { ref, onMounted, } from 'vue'
const helloRef = ref<InstanceType<typeof HelloWorld>>()
onMounted(()=>{
// 这里可以获取组件 HelloWorld 的 print 方法
helloRef.value?.print()
// Welcome to Your Vue.js + TypeScript App
})
</script>
对于 Vue 3.2 之后的组件,需要将暴露的属性通过 defineExpose 暴露出去。
使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。
为了在 <script setup> 组件中明确要暴露出去的属性,使用 defineExpose 编译器宏:
// HelloWorld.vue
<script lang="ts" setup>
interface Props{
msg: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(),{
msg: 'hello',
labels: ()=> ['one']
})
const print = ()=>{
console.log(props.msg)
}
defineExpose({
print
})
</script>
! 非空断言
在 TS 中 !用于告诉编译器变量不存在 undefined 或 null 的情况。
function myFunc(maybeNumber: number | undefined | null) {
// Type 'number | null | undefined' is not assignable to type 'number'.
// Type 'undefined' is not assignable to type 'number'.
const onlyNumber: number = maybeNumber; // Error
const ignoreUndefinedAndNull: number = maybeString!; //no problem
}
常用于开发者明确知道某个变量不是 undefined 或 null 的场景,有可能某个变量在最开始定义的时候为 undefined,中间已经完成了赋值,但是编译器还是会报错,这个时候可以使用 ! 明确其不存在 undefined 或 null 的情况。
interface IPersonInfo{
name: string,
age: number,
}
const person = ref<IPersonInfo>()
// 先进行赋值操作
const initPerson = (record: IPersonInfo)=>{
person.value = record
}
// ! 非空断言
const test = ()=>{
person.value!.name = 'Lily'
}
Provide/Inject + TypeScript 使用
索引签名 VS Record 类型
索引签名和 Record 类型都可以用来定义一个对象(Object)的 key 和 value 取值类型,使用上有些不同而已。
索引签名
索引签名的详细用法可以参考:www.jianshu.com/p/b00ad373f… 在 TypeScript 中语法如下:
type Human = {[key: string]: string}
// 等价 type Human = {[name: string]: string}
const man: Human = {
name: 'zhangsan',
job: 'worker',
}
其中 key 是用来增加可读性,并没有实际意义,也可以用其他字段表示。
可以限制 key 的取值范围:
type PositionIndex = 'x' | 'y'
type Position = {[k in PositionIndex]: number}
const point1: Position = {
x: 10,
y: 10
}
这里 Position 的 key 必须包括 PositionIndex 里所有取值,既要有 x 属性,又要有 y 属性:
可以使用 ?: 可选属性让 key 的取值为可选:
type PositionIndex = 'x' | 'y'
type Position = {[k in PositionIndex]?: number}
const point1: Position = {
x: 10,
}
与索引签名一起使用时,必须保持与索引签名一致的类型:
Record 类型
type People = Record<string, string>
const woman: People = {
name: 'lisi'
}
限制对象 key 的取值:
type PositionIndex = 'x' | 'y'
type Position = Record<PositionIndex, number>
const point1: Position = {
x: 10,
y: 1
}
同样这里的 point1 必须要有 x 和 y 两个属性:
与索引签名不同的是Record 类型并不能实现可选属性。
相同点是索引签名 和 Record 类型的 key 取值类型必须是 string | number | symbol
必须包括所有属性的理解
type PositionIndex = 'x' | 'y'
type Position = {[k in PositionIndex]: number}
const point1: Position = {
x: 10,
y: 10
}
// 或者
type PositionIndex = 'x' | 'y'
type Position = Record<PositionIndex, number>
const point1: Position = {
x: 10,
y: 1
}
上面两种写法都需要 point1 必须要有 x 和 y 两个属性,怎么理解呢?可以借用 keyof,
当我们使用 keyof 来获取 Position 的 key 时,会发现跟
type PositionIndex = 'x' | 'y'
// 等价
type AllKey = keyof Position
所以 point1 必须要有 x 和 y 两个属性
try...catch 错误信息提示
在 try...catch 语句中,有可能 catch 的 error 变量不是 Error 类型,要加一层判断:
try {
// ...
} catch (err) {
let message = '操作失败'
if (err instanceof Error) {
message = err.message
}
alert(message)
}
try...catch 返回类型处理
在 async...await 中的 try...catch 异常处理,需要返回 Promise<T> 的类型。这个时候的 catch 有两种处理方式。
一种是在 catch 里面 return 对应的类型,另一种是 throw(error)
let myPromise = Promise.resolve('Resolved Data');
async function myFunction(): Promise<string> {
try {
let resolvedValue = await myPromise;
return resolvedValue;
} catch (error) {
console.log(error);
//return Promise.resolve('test')
throw(error)
}
}
函数
type 定义函数
type SearchFn = (keyword: string) => void
const searchName: SearchFn = (name: string)=>{
console.log(name)
}
interface 定义函数
interface ISearchFn{
(key: string): void
// use `:` between the parameter list and the return type rather than `=>`.
}
const search: ISearchFn = (name: string)=>{
console.log(name)
}
注意 使用 : 在函数的参数和返回类型之间,而不是 =>
属性是函数类型
type Pagination = {
total: number
current: number
pageSize: number
showTotal: (total: number) => void
}
interface IPagination {
total: number
current: number
pageSize: number
showTotal: (total: number) => void
}
const paginationParams: Pagination = {
total: 0,
current: 1,
pageSize: 10,
showTotal: total => `共${total}条`,
}
获取字段类型
获取 interface 某个字段类型声明,hobbyT 就是 string | number
interface IPerson{
name: string
hobby: string | number
}
type hobbyT = IPerson['hobby']
获取 type 某个字段类型声明,hobbyData 就是 boolean | number
type TableData = {
id: number,
name: string,
hobby: boolean | number
}
type hobbyData = TableData['hobby']
?? 空值合并运算符
?? 是一个逻辑运算符,当左侧的操作数是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
与逻辑或运算符(||)不同,逻辑或运算符会在左侧操作数为 falsy 时,返回右侧操作数。
所以, ?? 相比较 || 只限制 null 和 undefined,更实用。
console.log( 0 ?? 42) // 0
console.log( 0 || 42) // 42