Vue中option的类型推断
如果大家有用ts写代码,会发现当我们写组件的option(选项)时,能够很好的提供类型推断,当然前提是你要使用Vue.extend()方法。
具体的使用大家可以参考我写的这篇博客,如何在vue中不借助vue-class-decorator实现ts类型推断。
那vue的类型是如何实现在参数中为this提供类型推断呢?
以下这段代码在javascript能够很好的工作,也很容易理解。但是当我们切换到ts做静态类型检查时,this
并不能很好的工作,那我们如何让this
能够提供类型推断呢?
export default {
data: {
first_name: "Anthony",
last_name: "Fu",
},
computed: {
full_name() {
return this.first_name + " " + this.last_name;
},
},
methods: {
hi() {
alert(this.full_name);
},
},
};
this提供类型
为了能让this
显示的推断类型,我们可以采取传参的方式
interface Context {
$injected: string
}
function bar(this: Context, a: number) {
this.$injected // 这样是能工作的
}
但是,如果我们传入Record参数类型(索引对象),这样就会有问题,它(ts)并不能很好提供类型校验了
type Methods = Record<string, (this: Context, ...args:any[]) => any>
const methods: Methods = {
bar(a: number) {
this.$injected // ok
}
}
methods.bar('foo', 'bar') // 没有提示错误,因为参数类型已经变为 `any[]`
而且也不能老是让用户,提供参数类型吧!这种体验是非常不友好的,所以为了实现类型校验,我们需要寻找另一种方法了。
ThisType
在了解了vue的代码之后,发现了ts一个很有用的内置类型 -ThisType
ThisType定义:通过ThisType
我们可以在对象字面量中键入this
,并提供通过上下文类型控制this
类型的便捷方式。它只有在--noImplicitThis
的选项下才有效
ThisType
可以影响所有的嵌套函数,那我们可以这样写了
type Methods = {
double: (a: number) => number
deep: {
nested: {
half: (a: number) => number
}
}
}
const methods: Methods & ThisType<Methods & Context> = {
double(a: number) {
this.$injected // ok
return a * 2
},
deep: {
nested: {
half(a: number) {
this.$injected // ok
return a / 2
}
}
}
}
methods.double(2) // ok
methods.double('foo') // error
methods.deep.nested.half(4) // ok
可以看到this
的类型推断已经生效了,但是有个缺点还是需要用户去定义方法的接口,那我们能不能自动推断类型呢?
实现define
可以的,通过函数来自动推断类型。
type Options<T> = {
methods?: T
} & ThisType<T & Context>
function define<T>(options: Options<T>) {
return options
}
define({
methods: {
foo() {
this.$injected // ok
},
},
})
方法已经能自动推断了,那么接下来,我们可以接着实现computed
和data
的类型推断
整个完整的demo如下:
/* ---- Type ---- */
export type ExtractComputedReturns<T extends any> = {
[key in keyof T]: T[key] extends (...args: any[]) => infer TReturn
? TReturn
: never
}
type Options<D = {}, C = {}, M = {}> = {
data: () => D
computed: C
methods: M
mounted: () => void
// and other options
}
& ThisType<D & M & ExtractComputedReturns<C>> // merge them together
function define<D, C, M>(options: Options<D, C, M>) {}
/* ---- Usage ---- */
define({
data() {
return {
first_name: "Anthony",
last_name: "Fu",
}
},
computed: {
fullname() {
return this.first_name + " " + this.last_name
},
},
methods: {
notify(msg: string) {
alert(msg)
}
},
mounted() {
this.notify(this.fullname)
},
})
其实define的原理就是Vue.extend能推断this
(上下文类型)的原理了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。