vue3 项目中TS常见用法之 ref() /reactive()/ defineProps() 使用的注意事项及用法
1、ref 创建的响应式对象 类型
vue3 文件中 当我们在 script
中添加 lang=“ts”
时候,编译模板会自动根据script 中定义的数据类型而推断出属性的类型(当没有声明属性类型时候)
比如:
以下单文件
<template>
<div class="my-ts">
This is a demo of TS.
<h3>{{ name }}</h3>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
const name = ref(333)
</script>
注意:在使用时候类型定义要与调用的方法保持一致,不然会导致对应的属性 没有该方法而报错;
比如:
<template>
<div class="my-ts">
This is a demo of TS.
<h3>{{ name }}</h3>
<el-button @click="handleChangeName">change name</el-button>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
const name = ref<string | number>(333)
const handleChangeName = ():void => {
name.value.toFixed(2)
console.log()
}
</script>
name.value.toFixed(2)
由于string 类型的属性是没有 toFixed() 方法的,故报错,如下图
若不想修改 初始化中的数据类型,则需要如下修改
<script setup lang="ts">
import { ref } from "vue"
const name = ref<string | number>(333)
const handleChangeName = ():void => {
// 将name.value 的 值断言为 number 类型
// (name.value as number).toFixed(2)
// 或者直接重新赋值为 number类型
name.value = 4.67890
const curName: string | number = name.value.toFixed(3)
console.log('curName',curName)
}
</script>
当我们给ref
指定复杂类型时候,通过Ref
类型声明或者调用 ref时传入一个泛型参数 来覆盖推断类型
import type {Ref} from "vue"
const age: Ref< String | Number> = ref(18)
如果泛型参数没有给定初始值,那么会得到一个undefined 类型
2、reactive() 创建对象的类型
reactive
创建的响应式,只能是对象类型,不能是基本类型;
创建对象类型:
<script lang="ts" setup>
import { reactive } from "vue"
// 对象
interface Person {
name: string;
age: number;
job?: string; // 可选属性,即该属性可有可无
changeJob: () => void;
}
const preson: Person = reactive({
name: 'Andy',
age: 18,
changeJob: () => {
preson.job = '专业搬砖'
}
})
</script>
创建数组对象
<script setup lang="ts">
// 数组
// 先声明对象中的各个属性的类型,
interface Item {
id: number;
name: string;
}
// 声明 index 的类型
interface Lists {
[index: number]: Item
}
const lists: Lists = reactive([
{
id: 1,
name: 'Andy'
},
{
id: 2,
name: 'Tom'
},
{
id: 3,
name: 'Jerry'
}
])
</script>
3.1、props 中的类型声明
<script setup lang="ts">
// 没有使用ts 的类型声明
const props = defineProps({
person: {
type: Object,
default: () => ({})
}
})
// 使用ts时
// 定义 Person 接口
interface Person{
name: string;
age: {
type: number,
required: true
};
job?: string; // 可选属性,即该属性可有可无
changeJob: () => void;
}
interface AgeIn {
age: number | string // 联合声明 age
}
const props = defineProps<{
person: Person,
age: AgeIn
}>()
// 当需要给默认值的时候,需要使用 widthDefaults()
// withDefaults 辅助函数提供了对默认值的类型检查,并确保返回的 props 的类型删除了已声明默认值的属性的可选标
// defineProps 在一个script 中只能调用一次,不能调用多次
// const ageProps = withDefaults(defineProps<AgeIn>(), {
// age: 12
// })
// 传递给 defineProps 的参数本身不能是一个导入类型, 只能是当前文件下的一个对象或者interface
</script>
3.2、当一个组件需要传递不同的数据结构和类型时候
父组件向子组件传递的所有参数中,基本类型、复杂类型参数都有的情况下:
首先定义一个接口 Props ,
其次使用 withDefaults() 检查默认值
若为 复杂类型数据,需要使用 箭头函数 return 出去各个子属性的默认值
<script lang="ts" setup>
interface Props {
either: '必传且限定'|'其中一个'|'值', // 利用TS:限定父组件传 either 的值
child: string|number,
sda?: string, // 未设置默认值,为 undefined
strData: string,
msg?: string
labels?: string[],
obj?:{name:string, age?: number}
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
// 复杂类型需要 return 出来默认值
labels: () => ['one', 'two'],
obj: () => { return {name: 'Andy', age:2} }
})
console.log('==props==', props)
</script>