目录
TypeScript 与 Vue
文档说明
vscode 插件说明
准备页面基本结构
defineProps与Typescript
defineEmits与Typescript
ref与Typescript
reactive与Typescript
computed与Typescript
事件对象与Typescript
模板Ref与Typescript
可选链操作符和非空断言
TypeScript 与 Vue
文档说明
英文文档:TypeScript with Composition API | Vue.js
中文文档:TypeScript 与组合式 API | Vue.js
vscode 插件说明
vue3 配合 ts 中,还需要额外安装一个 vscode 插件:Typescript Vue Plugin (Volar)
准备页面基本结构
main.ts
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
App.vue
<script setup lang="ts">
</script>
<template>
<div>
<h1>我是 App 组件</h1>
</div>
</template>
defineProps与Typescript
目标:掌握 defineProps 如何配合 ts 使用
defineProps js 写法
App.vue
<script setup lang="ts">
import Child from './components/Child.vue'
import { ref } from 'vue'
const money = ref(100)
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h1>我是 App 组件 --- {{ money }}</h1>
<Child :money="money"></Child>
</div>
</template>
components/Child.vue
<script setup lang="ts">
defineProps({
money: {
type: Number, // 定义类型
required: true, // 是否必传
// default: 10 // 默认值
}
})
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h3>我是 Child 组件 --- {{ money }}</h3>
</div>
</template>
defineProps ts 写法
通过 defineProps 函数的泛型,指定了 prop 的名字和类型。(vue 内部做了一些处理)
components/Child.vue
<script setup lang="ts">
// 1. 只要写在泛型里面的 prop 类型,就代表是必填的了
defineProps<{
money: number
}>()
// 2. 如果 prop 不是必传的
defineProps<{
money?: number
}>()
// 3. 通过解构指定默认值
const { money = 10 } = defineProps<{
money?: number
}>()
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h3>我是 Child 组件 --- {{ money }}</h3>
</div>
</template>
如果提供的默认值需要在模板中渲染,需要额外添加配置
Reactivity Transform | Vue.js
vite.config.ts
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
defineEmits与Typescript
目标:掌握 defineEmit 如何配合 ts 使用
defineEmits js 写法
App.vue
<script setup lang="ts">
import { ref } from 'vue'
import Child from './components/Child.vue'
const money = ref(100)
// 挣钱
const makeMoney = (childMoney: number) => {
money.value = money.value + childMoney
}
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h1>我是 App 组件</h1>
<Child :money="money" @makeMoney="makeMoney"></Child>
</div>
</template>
components/Child.vue
<script setup lang="ts">
const emit = defineEmits(['makeMoney'])
const makeMoney = () => {
emit('makeMoney', 10)
}
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h3>我是 Child 组件 --- {{ money }}</h3>
<button @click="makeMoney">挣钱</button>
</div>
</template>
defineEmits ts 写法
js 的写法只是接收了传递过来的自定义事件的名字。
通过 defineEmits 函数的泛型:指定了自定义事件的名字,还指定了自定义事件函数的参数和返回值的类型。(vue 内部做了一些处理)
<script setup lang="ts">
// defineEmits 传入对象类型,对象类型中是一个一个的匿名函数类型,这个对象类型不是用来直接给自定义事件数据定义的
// vue内部拿这个对象类型后要做组装处理,然后给父组件传递过来的自定义事件数据定义类型
// 语法
// const emit = defineEmits<{
// (e: '自定义事件名', 自定义事件函数参数: 自定义事件函数参数类型): 自定义事件函数返回值类型
// }>()
const emit = defineEmits<{
(e: 'makeMoney', childMoney: number): void
}>()
const makeMoney = () => {
emit('makeMoney', 10)
}
</script>
<template>
<div style="border: 3px solid #ccc;margin: 10px;">
<h3>我是 Child 组件 --- {{ money }}</h3>
<button @click="makeMoney">挣钱</button>
</div>
</template>
指定类型的好处:使用 emit 触发自定义事件时,不会传错参数。
ref与Typescript
目标:掌握 ref 配合 ts 如何使用
-
如果是简单数据类型,通过泛型指定值的类型,并且该类型可以省略
App.vue
<script setup lang="ts">
import { ref } from 'vue'
const money = ref<number>(100)
// 相当于
const money = ref(100)
</script>
<template>
<div>
<h1>我是 App 组件 --- {{ money }}</h1>
</div>
</template>
2.如果是复杂数据类型,通过泛型指定值的类型,并且推荐指定类型
App.vue
<script setup lang="ts">
import { ref } from 'vue'
// 不指定类型,会报错,并且没有提示
type User = {
id: number
name: string
age: number
}
const list = ref<User[]>([])
// 模拟后端返回数据
setTimeout(() => {
list.value = [
{ id: 1, name: 'zs', age: 18 },
{ id: 2, name: 'ls', age: 19 }
]
}, 1000)
</script>
<template>
<div>
<h1>我是 App 组件</h1>
</div>
</template>
reactive与Typescript
目标:掌握 reactive 配合 ts 如何使用
App.vue
<script setup lang="ts">
import { reactive } from 'vue'
// reactive 只适用于给具有明确属性的复杂数据。它可以自己推断类型,所以不需要指定类型
const user = reactive({
id: 1,
name: 'zs',
age: 18
})
// 如果指定类型,有两种写法
type User = {
id: number
name: string
age?: number
}
// 写法一
const user: User = reactive({
id: 1,
name: 'zs',
age: 18
})
// 写法二(泛型)
const user = reactive<User>({
id: 1,
name: 'zs',
age: 18
})
</script>
<template>
<div>
<h1>我是 App 组件</h1>
</div>
</template>
computed与Typescript
目标:掌握 computed 配合 typescript 如何使用
通过泛型可以指定 computed 计算属性返回值的类型,通常可以省略,因为它可以根据计算属性的返回值类型自动推导出来。
App.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
const count = ref(100)
const doubleCount = computed(() => {
return count.value * 2
})
const doubleCount = computed<number>(() => {
return count.value * 2
})
</script>
<template>
<div>
<h1>我是 App 组件 --- {{ count }} --- {{ doubleCount }}</h1>
</div>
</template>
事件对象与Typescript
目标:掌握事件对象配合 typescript 如何使用
App.vue
<script setup lang="ts">
// 1. 想要有事件对象上的属性提示,需要给事件对象指定类型(可以通过鼠标悬停到绑定的事件上,查看事件对象的类型)
const handleChange = (event: Event) => {
console.log(event.target)
}
// 1. 想要有事件目标源上的属性提示,需要给事件目标源做类型断言(可以通过 document.createElement 创建该元素,查看元素的类型)
const handleChange = (event: Event) => {
// const input = document.createElement('input')
console.log((event.target as HTMLInputElement).value)
}
</script>
<template>
<div>
<h1>我是 App 组件</h1>
<input type="text" @change="handleChange" />
</div>
</template>
模板Ref与Typescript
目标:掌握 ref 操作 DOM 时如何配合 Typescript 使用
App.vue
<script setup lang="ts">
import { ref } from 'vue'
const h1Ref = ref(null)
const getElement = () => {
// 报错,因为初始值是 null,无法从 null 身上获取其他属性。
console.log(h1.value.innerHTML)
}
// 通过 ref 获取 DOM 时,要通过泛型设置 DOM 类型
const h1Ref = ref<HTMLHeadingElement | null>(null)
const getElement = () => {
if (h1Ref.value) {
console.log(h1Ref.value.innerHTML)
}
}
</script>
<template>
<div>
<h1 ref="h1Ref">我是 App 组件</h1>
<button @click="getH1">获取 h1 元素</button>
</div>
</template>
可选链操作符和非空断言
目标:掌握 js 中的可选链操作符语法,掌握 ts 中的非空断言的使用语法
访问对象的深层属性时,但是不确定属性是否存在时:
类型守卫:对象中的某个属性存在时,才继续访问它后面的属性
可选链操作符( ?.
):对象中的某个属性存在时,才继续访问它后面的属性
非空断言:如果我们明确的知道对象的属性一定不会为空,那么可以使用非空断言 !
App.vue
<script setup lang="ts">
import { ref } from 'vue'
const h1Ref = ref<null | HTMLHeadingElement>(null)
const changeElement = () => {
// 方式一:类型守卫(使用if判断)
if (h1.value) {
console.log(h1.value.innerHTML)
}
// 方式二:可选链操作符(无法做赋值操作)
console.log(h1.value?.innerHTML)
// 方式三:非空断言
// 使用非空断言告诉 ts,h1.value 一定不为空
// 注意:非空断言一定要确保有该属性才能使用,不然使用非空断言会导致 bug
console.log(h1.value!.innerHTML)
}
</script>
<template>
<div>
<h1>我是 App 组件</h1>
<button ref="h1Ref" @click="changeElement">修改 h1 元素 innerHTML 内容</button>
</div>
</template>