Appearance
Vue3结合TypeScript使用
环境搭建
环境搭建这里就不详细介绍了,可以直接使用官方的方式创建
javascript
npm init vue@lastest这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:
javascript
✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
Scaffolding project in ./<your-project-name>...
Done.如果不确定是否要开启某个功能,你可以直接按下回车键选择 No。在项目被创建后,通过以下步骤安装依赖并启动开发服务器:
javascript
cd <your-project-name>
npm install
npm run devref()
ref()接受一个内部值,返回一个响应式、可更改的ref对象,此对象只有一个指向其内部值的property value。
类型定义
typescript
function ref<T>(value: T): Ref<UnwrapRef<T>>
interface Ref<T> {
value: T
}为ref()标注类型
ref()标注类型有三种方式:
1.通过泛型参数的形式来给ref()增加类型
typescript
import {ref} from 'vue'
const initCode = ref<string | number>('200')2.如果是遇到复杂点的类型,可以自定义interface然后泛型参数的形式传入
typescript
import {ref} from 'vue'
interface User{
name:string
age:string|number
}
const user = ref<User>({
name:'前端开发',
age:20
})3.通过使用Ref这个类型为ref内的值指定一个更复杂的类型
typescript
import {ref} from 'vue'
import type {Ref} from 'vue'
const initCode:Ref<string|number> = ref('200')比较推荐使用前两种方式,前两种方式其实都是以泛型的形式来标注类型的
第三种方式需要额外的引入,所以不是很推荐
reactive()
reactive()返回一个对象的响应式代理
类型定义
typescript
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>为reactive()标注类型
reactive()标注类型有两种方式:
1.直接给声明的变量添加类型
typescript
import {reactive} from 'vue'
interface User{
name:string
age:string|name
}
const user:User = reactive({
name:'前端开发',
age:'20'
})2.通过泛型参数的形式来给 reactive()增加类型
typescript
import {reactive} from 'vue'
interface User {
name:string,
age:string | number
}
const user = reactive<User>({
name:'前端开发',
age:'20'
})不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。推荐直接给声明的变量添加类型。
computed()
computed标注类型有两种方式
1.从其计算函数的返回值上推导出类型
typescript
import {ref,computed} from 'vue'
const count = ref<number>(0)
// 推导得到的类型:ComputedRef<string>
const user = computed(() => count.value + '前端开发爱好者')2.通过泛型参数显式指定 computed() 类型
typescript
const user = computed<string>( () => {
return '前端爱好者'
})自动推导类型虽然简单快捷,但是还是希望手动的去指定其类型,这样更加利于代码的可维护性,所以这里推荐使用通过泛型参数显式指定 computed() 类型
defineProps()
为了在声明 props 选项时获得完整的类型推断支持,我们可以使用 defineProps API,它将自动地在 script setup 中使用
1.从它的参数中推导类型
typescript
const props = defineProps({
name:{
type:string,
required:true
},
age:number
})2.通过泛型参数来定义props的类型
typescript
const props = defineProps<{
name:string,
age?:number
}>当然了,也可以把以上的泛型参数定义成一个单独的 interface
typescript
interface Props {
name: string
age?: number
}
const props = defineProps<Props>()以上的两种方式虽然都可以很方便的
标注类型, 但是失去了对props定义默认值的能力
目前官方也给出了解决方案,但是目前这个方案还处于实验性,并且需要显式地选择开启。
typescript
// vite.config.js
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}通过对 defineProps() 的响应性解构来添加默认值:
typescript
<script setup lang="ts">
interface Props {
name: string
age?: number
}
const { name = '前端开发爱好者', age = 100 } = defineProps<Props>()
</script>defineEmits()、defineExpose()
provide()
provide()供给一个值,可以被后代组件注入
类型定义
typescript
function provide<T>(key: InjectionKey<T> | string, value: T): void为 provide() 标注类型, Vue 提供了一个 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,可以用来在提供者和消费者之间同步注入值的类型
typescript
import type { InjectionKey } from 'vue'
// 建议声明 key (name) 放到公共的文件中
// 这样就可以在 inject 的时候直接导入使用
const name = Symbol() as InjectionKey<string>
provide(name, '前端开发爱好者') // 若提供的是非字符串值会导致错误以上方式是通过定义 key 的类型来标注类型的,还有一种方式直接 key 采用字符串的形式添加
inject()
inject()注入一个由祖先组件或整个应用供给的值
类型定义
typescript
// 没有默认值
function inject<T>(key: InjectionKey<T> | string): T | undefined
// 带有默认值
function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
// 使用工厂函数
function inject<T>(
key: InjectionKey<T> | string,
defaultValue: () => T,
treatDefaultAsFactory: true
): Tprovide() 的 key 的类型是声明式提供的话(provide()类型标注的第一种形式)
inject() 可以直接导入声明的 key 来获取父级组件提供的值
typescript
// 由外部导入
const name = Symbol() as InjectionKey<string>
const injectName = inject(name)如果 provide() 的 key 直接使用的字符串形式添加的, 需要通过泛型参数声明
typescript
const injectName = inject<string>('name')模板 ref
模板 ref 需要通过一个显式指定的泛型参数和一个初始值 null 来创建
typescript
<img ref="el" class="logo" :src="Logo" alt="" />
const el = ref<HTMLImageElement | null>(null)组件ref
有时,你可能需要为一个子组件添加一个模板 ref,以便调用它公开的方法
typescript
<!-- Child.vue -->
<script setup lang="ts">
const handleLog = () => console.log('前端开发爱好者')
defineExpose({
open
})
</script>为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:
typescript
<!-- parent.vue -->
<script setup lang="ts">
import Child from './Child.vue'
// 为子组件 ref 声明类型
const child = ref<InstanceType<typeof Child> | null>(null)
// 调用子组件中的方法
const getChildHandleLog = () => {
child.value?.handleLog()
}
</script>事件处理器
原生的 DOM 事件标注类型
typescript
<template>
<input type="text" @change="handleChange" />
</template>
<script setup lang="ts">
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
</script>