至于技术栈为什么由 react
转向 vue3
,也是因为今年换了新工作,公司技术栈以vue3
为主,刚好前段时间又接手了一个项目,就直接采用 Vue3
script setup
typescript
开发,于是今天就想给大家分享下 script setup
结合 typescript
使用的一些技巧,如果这些技巧能够帮助到你,记得给我点个赞呦
环境搭建这里就不详细介绍了,可以直接使用官方的方式创建
npm init vue@latest
这一指令将会安装并执行 create-vue
,它是 Vue
官方的项目脚手架工具。你将会看到一些诸如 TypeScript
和测试
支持之类的可选功能提示:
✔ 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 ./...
Done.
如果不确定是否要开启某个功能,你可以直接按下回车键选择 No
。在项目被创建后,通过以下步骤安装依赖并启动开发服务器:
cd
npm install
npm run dev
这里就不做过多的讲解了,这篇文章的重点还是在 script setup
typescript
结合使用上
ref()
接受一个内部值,返回一个响应式的、可更改的 ref
对象,此对象只有一个指向其内部值的 property .value
。
function ref(value: T): Ref>
interface Ref {
value: T
}
ref()
标注类型有三种方式:
通过泛型参数的形式来给 ref()
增加类型
import { ref } from 'vue'
const initCode = ref('200')
如果是遇到复杂点的类型,可以自定义 interface
然后泛型参数的形式传入
import { ref } from 'vue'
interface User {
name: string
age: string | number
}
const user = ref({
name:'前端开发爱好者',
age: 20
})
通过使用 Ref
这个类型为 ref
内的值指定一个更复杂的类型
import { ref } from 'vue'
import type { Ref } from 'vue'
const initCode: Ref = ref('200')
比较推荐使用前两种
方式,前两种方式其实都是以泛型
的形式来标注类型的
第三种方式需要额外的引入:
import type { Ref } from 'vue'
所以不是很推荐(本着能少写一行是一行原则)
reactive()
返回一个对象的响应式代理。
function reactive(target: T): UnwrapNestedRefs
reactive()
标注类型有两种方式:
直接给声明的变量添加类型
import { reactive } from 'vue'
interface User {
name: string
age: string | number
}
const user:User = reactive({
name:"前端开发爱好者",
age:'20'
})
通过泛型参数的形式来给 reactive()
增加类型
import { reactive } from 'vue'
interface User {
name: string
age: string | number
}
const user = reactive({
name:"前端开发爱好者",
age:'20'
})
不推荐
使用 reactive()
的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。推荐直接给声明的变量添加类型
。
接受一个 getter
函数,返回一个只读的响应式 ref
对象,即 getter
函数的返回值。它也可以接受一个带有 get
和 set
函数的对象来创建一个可写的 ref
对象。
// 只读
function computed(
getter: () => T,
debuggerOptions?: DebuggerOptions
): Readonly>>
// 可写的
function computed(
options: {
get: () => T
set: (value: T) => void
},
debuggerOptions?: DebuggerOptions
): Ref
computed()
标注类型有两种方式:
从其计算函数的返回值上推导出类型
import { ref, computed } from 'vue'
const count = ref(0)
// 推导得到的类型:ComputedRef
const user = computed(() => count.value + '前端开发爱好者')
通过泛型参数显式指定 computed()
类型
const user = computed(() => {
// 若返回值不是 string 类型则会报错
return '前端开发爱好者'
})
自动推导类型虽然简单快捷,但是还是希望手动
的去指定
其类型,这样更加利于代码的可维护性,所以这里推荐大家使用通过泛型参数显式指定 computed()
类型
为了在声明 props
选项时获得完整的类型推断支持,我们可以使用 defineProps
API,它将自动地在 script setup
中使用
从它的参数中推导类型:
const props = defineProps({
name: { type: String, required: true },
age: Number
})
通过泛型参数来定义 props
的类型
const props = defineProps<{
name: string
age?: number
}>()
当然了,我们也可以把以上的泛型参数定义成一个单独的 interface
interface Props {
name: string
age?: number
}
const props = defineProps()
以上的两种方式虽然都可以很方便的
标注类型
, 但是失去了对props
定义默认值的能力
目前官方也给出了解决方案,但是目前这个方案还处于实验性,并且需要显式地选择开启
。
// vite.config.js
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
通过对 defineProps()
的响应性解构来添加默认值:
为了在声明 emits
选项时获得完整的类型推断支持,我们可以使用 defineEmits
API,它将自动地在 script setup
中使用
defineEmits()
标注类型直接推荐泛型
形式
import type { GlobalTheme } from 'naive-ui'
const emit = defineEmits<{
(e: 'setThemeColor', val: GlobalTheme): void
}>()
虽然官方还推荐了运行时
自动推导的一种形式,但是本人不是很推荐
defineExpose()
编译器宏来显式指定在 script setup
组件中要暴露出去的 property
,使得父组件通过模板ref
的方式获取到当前组件的实例
defineExpose()
类型推导直接使用参数类型自动推导即可
为了获取 MyModal
的类型,我们首先需要通过 typeof
得到其类型,再使用 TypeScript
内置的 InstanceType
工具类型来获取其实例类型:
原生的 DOM 事件标注类型