若是你們有用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
(上下文類型)的原理了