1
1
# TypeScript 与选项式 API {#typescript-with-options-api}
2
2
3
- > 这一章假设你已经阅读过了这篇 [ 搭配 TypeScript 使用 Vue] ( ./overview ) 的文档 。
3
+ > 这一章假设你已经阅读了 [ 搭配 TypeScript 使用 Vue] ( ./overview ) 的概览 。
4
4
5
5
::: tip
6
- 虽然 Vue 的确支持在选项式 API 中使用 TypeScript,但还是推荐你搭配 TypeScript 和组合式 API 来使用 Vue,因为它提供了更简单、高效和更可靠的类型推导 。
6
+ 虽然 Vue 的确支持在选项式 API 中使用 TypeScript,但还是推荐通过 TypeScript 与组合式 API 来使用 Vue,因为它提供了更简单、更高效和更可靠的类型推导 。
7
7
:::
8
8
9
- ## 为组件 props 标注类型 {#typing-component-props}
9
+ ## 为组件的 prop 标注类型 {#typing-component-props}
10
10
11
- 选项式 API 中对 props 的类型推导需要用 ` defineComponent() ` 来包裹组件。有了它,Vue 才可以通过 ` props ` 来推断出 props 的类型,另外还有一些其他的选项, 比如 ` required: true ` 和 ` default ` :
11
+ 选项式 API 中对 prop 的类型推导需要用 ` defineComponent() ` 来包裹组件。有了它,Vue 才可以通过 ` props ` 以及一些额外的选项, 比如 ` required: true ` 和 ` default ` 来推导出 prop 的类型 :
12
12
13
13
``` ts
14
14
import { defineComponent } from ' vue'
15
15
16
16
export default defineComponent ({
17
- // 启用类型推导
17
+ // 启用了类型推导
18
18
props: {
19
19
name: String ,
20
20
id: [Number , String ],
@@ -30,9 +30,9 @@ export default defineComponent({
30
30
})
31
31
```
32
32
33
- 然而,这种运行时 props 选项仅支持使用构造函数来作为一个 prop 的类型,而没有办法指定多层级对象或函数签名之类的复杂类型 。
33
+ 然而,这种运行时 ` props ` 选项仅支持使用构造函数来作为一个 prop 的类型——没有办法指定多层级对象或函数签名之类的复杂类型 。
34
34
35
- 要标记更复杂的 props 类型, 我们可以使用 ` PropType ` 这个工具类型。
35
+ 我们可以使用 ` PropType ` 这个工具类型来标记更复杂的 prop 类型:
36
36
37
37
``` ts
38
38
import { defineComponent , PropType } from ' vue'
@@ -46,27 +46,27 @@ interface Book {
46
46
export default defineComponent ({
47
47
props: {
48
48
book: {
49
- // 比 `Object` 提供更确定的类型
49
+ // 提供相对 `Object` 更确定的类型
50
50
type: Object as PropType <Book >,
51
51
required: true
52
52
},
53
- // 也可以标记函数类型
53
+ // 也可以标记函数
54
54
callback: Function as PropType <(id : number ) => void >
55
55
},
56
56
mounted() {
57
57
this .book .title // string
58
58
this .book .year // number
59
59
60
- // TS 错误:类型为 'string' 的参数无法
61
- // 赋值给类型为 'number' 的参数
60
+ // TS Error: argument of type 'string' is not
61
+ // assignable to parameter of type 'number'
62
62
this .callback ?.(' 123' )
63
63
}
64
64
})
65
65
```
66
66
67
- ### 约定 {#caveats}
67
+ ### 注意事项 {#caveats}
68
68
69
- 因为一个 TypeScript 的 [ 设计限制] ( https://github.com/microsoft/TypeScript/issues/38845 ) ,你在使用函数作为 prop 的 ` validator ` 和 ` default ` 选项值时需要格外小心, 确保使用箭头函数:
69
+ 因为一个 TypeScript 的 [ 设计限制] ( https://github.com/microsoft/TypeScript/issues/38845 ) ,你在使用函数作为 prop 的 ` validator ` 和 ` default ` 选项值时需要格外小心—— 确保使用箭头函数:
70
70
71
71
``` ts
72
72
import { defineComponent , PropType } from ' vue'
@@ -92,9 +92,9 @@ const Component = defineComponent({
92
92
93
93
这会防止 Typescript 将 ` this ` 根据函数内的环境作出不符合我们期望的类型推导。
94
94
95
- ## 为组件的 emits 标注类型 {#typing-component-emits}
95
+ ## 为组件的 emit 标注类型 {#typing-component-emits}
96
96
97
- 我们可以使用对象值作为 ` emits ` 选项的值,为所触发的事件声明期望的载荷内容类型。并且触发到所有未声明的事件时都会抛出一个类型错误 :
97
+ 我们可以为使用了对象语法作为 ` emits ` 选项所触发的事件声明期望的载荷内容类型。并且,所有未声明的事件调用时都会抛出一个类型错误 :
98
98
99
99
``` ts
100
100
import { defineComponent } from ' vue'
@@ -120,7 +120,7 @@ export default defineComponent({
120
120
121
121
## 为计算属性标记类型 {#typing-computed-properties}
122
122
123
- 一个计算属性可以根据其返回值来推导得出类型 :
123
+ 一个计算属性根据其返回值来推导其类型 :
124
124
125
125
``` ts
126
126
import { defineComponent } from ' vue'
@@ -142,7 +142,7 @@ export default defineComponent({
142
142
})
143
143
```
144
144
145
- 在某些场景中,你可能想要显式的标记出计算属性的类型以确保实现是正确的 :
145
+ 在某些场景中,你可能想要显式地标记出计算属性的类型以确保其实现是正确的 :
146
146
147
147
``` ts
148
148
import { defineComponent } from ' vue'
@@ -154,12 +154,12 @@ const Component = defineComponent({
154
154
}
155
155
},
156
156
computed: {
157
- // 显式标注出返回值类型作为此计算属性类型
157
+ // 显式标注返回类型
158
158
greeting(): string {
159
159
return this .message + ' !'
160
160
},
161
161
162
- // 标注一个可写的计算属性的类型
162
+ // 标注一个可写的计算属性
163
163
greetingUppercased: {
164
164
get(): string {
165
165
return this .greeting .toUpperCase ()
@@ -172,7 +172,7 @@ const Component = defineComponent({
172
172
})
173
173
```
174
174
175
- 显式的类型标注可能在某些 TypeScript 无法推导类型的循环引用的边界情况下是必须指定的 。
175
+ 在某些 TypeScript 因循环引用而无法推导类型的情况下,可能必须进行显式的类型标注 。
176
176
177
177
## 为事件处理器标注类型 {#typing-event-handlers}
178
178
@@ -183,7 +183,7 @@ const Component = defineComponent({
183
183
export default {
184
184
methods: {
185
185
handleChange(event) {
186
- // `event` 隐式定位 `any` 类型
186
+ // `event` 隐式地标注为 `any` 类型
187
187
console.log(event.target.value)
188
188
}
189
189
}
@@ -195,7 +195,7 @@ export default {
195
195
</template>
196
196
```
197
197
198
- 没有类型标注时,这个 ` event ` 参数会隐式定为类型 ` any ` 。这也会在 ` tsconfig.json ` 中配置了 ` "strict": true ` 或 ` "noImplicitAny": true ` 时报出一个 TS 错误。因此,建议显式地为事件处理器的参数标注类型。此外,你可能需要显式地强制转换 ` event ` 上的属性 :
198
+ 没有类型标注时,这个 ` event ` 参数会隐式地标注为 ` any ` 类型 。这也会在 ` tsconfig.json ` 中配置了 ` "strict": true ` 或 ` "noImplicitAny": true ` 时抛出一个 TS 错误。因此,建议显式地为事件处理器的参数标注类型。此外,你可能需要显式地强制转换 ` event ` 上的 property :
199
199
200
200
``` ts
201
201
export default {
@@ -207,9 +207,9 @@ export default {
207
207
}
208
208
```
209
209
210
- ## 扩充全局属性 {#augmenting-global-properties}
210
+ ## 扩充全局 property {#augmenting-global-properties}
211
211
212
- 某些插件通过 [ ` app.config.globalProperties ` ] ( /api/application.html#app-config-globalproperties ) 为所有组件都全局安装了一些属性 。举个例子,我们可能为了请求数据 安装了 ` this.$http ` ,或者为了国际化翻译安装了 ` this.$translate ` 。为了使 TypeScript 更好地支持这个行为,Vue 暴露了一个 ` ComponentCustomProperties ` 接口,它被设计成通过 [ TypeScript 模块扩充] ( https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation ) 来进行属性扩充 :
212
+ 某些插件通过 [ ` app.config.globalProperties ` ] ( /api/application.html#app-config-globalproperties ) 为所有组件都安装了全局可用的 property 。举个例子,我们可能为了请求数据而安装了 ` this.$http ` ,或者为了国际化而安装了 ` this.$translate ` 。为了使 TypeScript 更好地支持这个行为,Vue 暴露了一个被设计为可以通过 [ TypeScript 模块扩充] ( https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation ) 来扩充的 ` ComponentCustomProperties ` 接口 :
213
213
214
214
``` ts
215
215
import axios from ' axios'
@@ -222,15 +222,15 @@ declare module 'vue' {
222
222
}
223
223
```
224
224
225
- 你也可以看看 :
225
+ 参考 :
226
226
227
227
- [ 对组件类型扩展的 TypeScript 单元测试] ( https://github.com/vuejs/core/blob/main/test-dts/componentTypeExtensions.test-d.tsx )
228
228
229
229
### 类型扩充的位置 {#type-augmentation-placement}
230
230
231
- 我们可以将这些类型扩充放在一个 ` .ts ` 文件或一个以整个项目为范围的 ` *.d.ts ` 文件中。无论哪一种,你都需要在 ` tsconfig.json ` 中将其引入。对于库或插件作者,这个文件应该在 ` package.json ` 的 ` type ` 属性中被列出 。
231
+ 我们可以将这些类型扩充放在一个 ` .ts ` 文件,或是一个以整个项目为范围的 ` *.d.ts ` 文件中。无论哪一种,确保在 ` tsconfig.json ` 中将其引入。对于库或插件作者,这个文件应该在 ` package.json ` 的 ` type ` property 中被列出 。
232
232
233
- In order to take advantage of module augmentation, you will need to ensure the augmentation is placed in a [ TypeScript module ] ( https://www.typescriptlang.org/docs/handbook/modules.html ) . That is to say, the file needs to contain at least one top-level ` import ` or ` export ` , even if it is just ` export {} ` . If the augmentation is placed outside of a module, it will overwrite the original types rather than augmenting them !
233
+ 为了利用模块扩充的优势,你需要确保将扩充的模块放在 [ TypeScript 模块 ] ( https://www.typescriptlang.org/docs/handbook/modules.html ) 中。 也就是说,该文件需要包含至少一个顶级的 ` import ` 或 ` export ` ,即使它只是 ` export {} ` 。如果扩充被放在模块之外,它将覆盖原始类型,而不是扩充 !
234
234
235
235
## 扩充自定义选项 {#augmenting-custom-options}
236
236
@@ -246,7 +246,7 @@ export default defineComponent({
246
246
})
247
247
```
248
248
249
- 没有确切的类型标注,这个钩子函数的参数会隐式定为 ` any ` 类型。我们可以为 ` ComponentCustomOptions ` 接口扩充自定义的选项来支持:
249
+ 如果没有确切的类型标注,这个钩子函数的参数会隐式地标注为 ` any ` 类型。我们可以为 ` ComponentCustomOptions ` 接口扩充自定义的选项来支持:
250
250
251
251
``` ts
252
252
import { Route } from ' vue-router'
@@ -258,11 +258,11 @@ declare module 'vue' {
258
258
}
259
259
```
260
260
261
- 现在这个 ` beforeRouterEnter ` 选项会被准确地类型化。注意这只是一个例子, 像 ` vue-router ` 这样类型完备的库应该在它们自己的类型定义中自动执行这些扩充 。
261
+ 现在这个 ` beforeRouterEnter ` 选项会被准确地类型化。注意这只是一个例子—— 像 ` vue-router ` 这种类型完备的库应该在它们自己的类型定义中自动执行这些扩充 。
262
262
263
- 这种类型扩充和全局属性扩充受到 [ 相同的限制] ( #type-augmentation-placement ) 。
263
+ 这种类型扩充和全局 property 扩充受到 [ 相同的限制] ( #type-augmentation-placement ) 。
264
264
265
- 你也可以看看 :
265
+ 参考 :
266
266
267
267
- [ 对组件类型扩展的 TypeScript 单元测试] ( https://github.com/vuejs/core/blob/main/test-dts/componentTypeExtensions.test-d.tsx )
268
268
0 commit comments