若是你们有用ts写代码,会发现当咱们写组件的option(选项)时,可以很好的提供类型推断,固然前提是你要使用Vue.extend()方法。javascript
具体的使用你们能够参考我写的这篇博客,如何在vue中不借助vue-class-decorator实现ts类型推断。vue
vue2中使用tsjava
那vue的类型是如何实如今参数中为this提供类型推断呢?segmentfault
如下这段代码在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)并不能很好提供类型校验了code
type Methods = Record<string, (this: Context, ...args:any[]) => any> const methods: Methods = { bar(a: number) { this.$injected // ok } } methods.bar('foo', 'bar') // 没有提示错误,由于参数类型已经变为 `any[]`
并且也不能总是让用户,提供参数类型吧!这种体验是很是不友好的,因此为了实现类型校验,咱们须要寻找另外一种方法了。对象
在了解了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
的类型推断已经生效了,可是有个缺点仍是须要用户去定义方法的接口,那咱们能不能自动推断类型呢?
能够的,经过函数来自动推断类型。
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
(上下文类型)的原理了