From cb33da466e39acfa2401f2cd28f27aef957979be Mon Sep 17 00:00:00 2001
From: jaywcjlove <398188662@qq.com>
Date: Sun, 4 Dec 2022 17:44:56 +0800
Subject: [PATCH] doc: update vue.md #10 add typescript example
---
docs/vue.md | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 428 insertions(+)
diff --git a/docs/vue.md b/docs/vue.md
index 79d73db..539871a 100644
--- a/docs/vue.md
+++ b/docs/vue.md
@@ -677,6 +677,434 @@ const value = inject(ProvideKey)
+Vue 中使用 TypeScript
+---
+
+### 为组件的 props 标注类型
+
+
+当使用 `
+```
+
+对同一个文件中的一个接口或对象类型字面量的引用:
+
+```ts
+interface Props {/* ... */}
+
+defineProps()
+```
+
+#### Props 解构默认值
+
+```ts
+export interface Props {
+ msg?: string
+ labels?: string[]
+}
+
+const props = withDefaults(defineProps(), {
+ msg: 'hello',
+ labels: () => ['one', 'two']
+})
+```
+
+使用目前为实验性的响应性语法糖
+
+```html
+
+```
+
+### 为组件的 emits 标注类型
+
+```html
+
+```
+
+### 为 ref() 标注类型
+
+ref 会根据初始化时的值推导其类型:
+
+```ts
+import { ref } from 'vue'
+import type { Ref } from 'vue'
+
+const year: Ref = ref('2020')
+
+year.value = 2020 // 成功!
+```
+
+### 为 reactive() 标注类型
+
+```ts
+import { reactive } from 'vue'
+
+interface Book {
+ title: string
+ year?: number
+}
+
+const book: Book = reactive({
+ title: 'Vue 3 指引'
+})
+```
+
+### 为 computed() 标注类型
+
+你还可以通过泛型参数显式指定类型:
+
+```ts
+const double = computed(() => {
+ // 若返回值不是 number 类型则会报错
+})
+```
+
+### 为事件处理函数标注类型
+
+
+```html
+
+
+
+
+
+```
+
+显式地为事件处理函数的参数标注类型
+
+```ts
+function handleChange(event: Event) {
+ const target = event.target as HTMLInputElement
+ console.log(target.value)
+}
+```
+
+### 为 provide / inject 标注类型
+
+```ts
+import { provide, inject } from 'vue'
+import type { InjectionKey } from 'vue'
+
+const key = Symbol() as InjectionKey
+// 若提供的是非字符串值会导致错误
+provide(key, 'foo')
+// foo 的类型:string | undefined
+const foo = inject(key)
+```
+
+### 为模板引用标注类型
+
+```html
+
+
+
+
+
+```
+
+### 为组件模板引用标注类型
+
+```html
+
+
+```
+
+使用 TypeScript 内置的 `InstanceType` 工具类型来获取其实例类
+
+```html
+
+
+```
+
+### 选项式 API 为组件的 props 标注类型
+
+
+```ts
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+ // 启用了类型推导
+ props: {
+ name: String,
+ id: [Number, String],
+ msg: { type: String, required: true },
+ metadata: null
+ },
+ mounted() {
+ // 类型:string | undefined
+ this.name
+ // 类型:number|string|undefined
+ this.id
+ // 类型:string
+ this.msg
+ // 类型:any
+ this.metadata
+ }
+})
+```
+
+使用 PropType 这个工具类型来标记更复杂的 props 类型
+
+```ts
+import { defineComponent } from 'vue'
+import type { PropType } from 'vue'
+
+interface Book {
+ title: string
+ author: string
+ year: number
+}
+
+export default defineComponent({
+ props: {
+ book: {
+ // 提供相对 `Object` 更确定的类型
+ type: Object as PropType,
+ required: true
+ },
+ // 也可以标记函数
+ callback: Function as PropType<(id: number) => void>
+ },
+ mounted() {
+ this.book.title // string
+ this.book.year // number
+
+ // TS Error: argument of type 'string' is not
+ // assignable to parameter of type 'number'
+ this.callback?.('123')
+ }
+})
+```
+
+### 选项式 API 为组件的 emits 标注类型
+
+```ts
+import { defineComponent } from 'vue'
+
+type Payload = { bookName: string }
+
+export default defineComponent({
+ emits: {
+ addBook(payload: Payload) {
+ // 执行运行时校验
+ return payload.bookName.length > 0
+ }
+ },
+ methods: {
+ onSubmit() {
+ this.$emit('addBook', {
+ bookName: 123 // 类型错误
+ })
+ // 类型错误
+ this.$emit('non-declared-event')
+ }
+ }
+})
+```
+
+### 选项式 API 为计算属性标记类型
+
+
+计算属性会自动根据其返回值来推导其类型:
+
+```ts
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+ data() {
+ return {
+ message: 'Hello!'
+ }
+ },
+ computed: {
+ greeting() {
+ return this.message + '!'
+ }
+ },
+ mounted() {
+ this.greeting // 类型:string
+ }
+})
+```
+
+在某些场景中,你可能想要显式地标记出计算属性的类型以确保其实现是正确的:
+
+```ts
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+ data() {
+ return {
+ message: 'Hello!'
+ }
+ },
+ computed: {
+ // 显式标注返回类型
+ greeting(): string {
+ return this.message + '!'
+ },
+
+ // 标注一个可写的计算属性
+ greetingUppercased: {
+ get(): string {
+ return this.greeting.toUpperCase()
+ },
+ set(newValue: string) {
+ this.message = newValue.toUpperCase()
+ }
+ }
+ }
+})
+```
+
+### 选项式 API 为事件处理函数标注类型
+
+```ts
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+ methods: {
+ handleChange(event: Event) {
+ console.log((event.target as HTMLInputElement).value)
+ }
+ }
+})
+```
+
+### 选项式 API 扩展全局属性
+
+```ts
+import axios from 'axios'
+
+declare module 'vue' {
+ interface ComponentCustomProperties {
+ $http: typeof axios
+ $translate: (key: string) => string
+ }
+}
+```
+
+#### 类型扩展的位置
+
+我们可以将这些类型扩展放在一个 `.ts` 文件,或是一个影响整个项目的 `*.d.ts` 文件中
+
+```ts
+// 不工作,将覆盖原始类型。
+declare module 'vue' {
+ interface ComponentCustomProperties {
+ $translate: (key: string) => string
+ }
+}
+```
+
+---
+
+```ts
+// 正常工作。
+export {}
+
+declare module 'vue' {
+ interface ComponentCustomProperties {
+ $translate: (key: string) => string
+ }
+}
+```
+
+### 选项式 API 扩展自定义选项
+
+某些插件,比如 vue-router,提供了一些自定义的组件选项,比如 beforeRouteEnter:
+
+```ts
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+ beforeRouteEnter(to, from, next) {
+ // ...
+ }
+})
+```
+
+如果没有确切的类型标注,这个钩子函数的参数会隐式地标注为 `any` 类型。我们可以为 `ComponentCustomOptions` 接口扩展自定义的选项来支持:
+
+```ts
+import { Route } from 'vue-router'
+
+declare module 'vue' {
+ interface ComponentCustomOptions {
+ beforeRouteEnter?(
+ to: Route,
+ from: Route,
+ next: () => void
+ ): void
+ }
+}
+```
+
API 参考
---