背景 我個人很喜歡TypeScript也很喜歡Vue,但在兩者共同使用的時候遇到一些問題。 Vue的實例化對象代理了所有實際ViewModel對象,具體可參見官方文檔( http://vuejs.org.cn/guide/instance.html 屬性與方法) Vue的屬性與方法: 每個 Vue ...
背景
我個人很喜歡TypeScript也很喜歡Vue,但在兩者共同使用的時候遇到一些問題。
Vue的實例化對象代理了所有實際ViewModel對象,具體可參見官方文檔(
http://vuejs.org.cn/guide/instance.html#屬性與方法)
Vue的屬性與方法:
每個 Vue 實例都會代理其 data 對象里所有的屬性
實際上vue實例不僅僅是代理了data屬性,還代理了methods屬性、computed屬性等,可以通過 這篇文檔 看到。那麼怎麼在TypeScript裡面通過vue實例訪問data屬性和methods屬性裡面的變數是最大問題,否則就沒辦法使用TS的最大的作用——強類型檢查。
如下圖可以看到:

雖然實際上vm.xxcanghaiFn是可用的,但是過不了TypeScript的編輯檢查,提示不在'xxcanghaiFn'不在'Vue'類型中。
因為類型'Vue'中肯定只有內部方法,自然會報錯,雖然我們可以通過<any>
語法強制使語法檢查失效,如下代碼:
var vm: any = new Vue({//vm變數增加any聲明
el: "#app",
data: {
xxcanghaiData: "xxcanghai"
},
methods: {
xxcanghaiFn: function () { }
}
});
vm.xxcanghaiFn//無編譯器報錯
雖然沒有編譯器報錯,但同時也無法再使用TS提供的智能補全,強類型檢查等功能。這就跟直接寫js沒有任何區別了。
解決方案
- 將data屬性,以及methods等需要合併進vue類型的對象分開寫
- 利用TypeScript的
typeof
和declare
關鍵字將類型合併聲明。 - 最後new Vue時強制用
<any>
聲明並賦值。
如下代碼:
//核心聲明,利用typeof將data和methods屬性合併進Vue類型
declare var VM: typeof vmData & typeof vmMethods & vuejs.Vue;
var vmData = {
xxcanghaiData: "xxcanghai"
};
var vmMethods = {
xxcanghaiFn: () => { }
}
var vm: typeof VM = <any>new Vue({
el: "#app",
data: vmData,
methods: <any>vmMethods
});
效果如下,既可以實現識別Vue內置函數及屬性:

也能實現識別我們自定義的data屬性和methods屬性中的值:

關於Vue中的計算屬性類型
Vue中有一種特殊的ViewModel的屬性——計算屬性。
計算屬性在使用ts的強類型的時候就會出錯,代碼如下:
declare var VM: vuejs.Vue & typeof vmComputed;
var vmComputed = {
/**
* 字元串計算屬性
*/
xxcanghaiCom: function () {
return "xxcanghaiCom";
}
}
var vm: typeof VM = <any>new Vue({
el: "#app",
computed: <any>vmComputed
});
計算屬會被ts的類型系統識別為一個函數,而出現函數相關的方法,此時調用字元串方法自然會報錯。如圖:

雖然計算屬性實際上確實是一個函數,但是我們希望能夠把計算屬性拿來當一個字元串變數來使用。
TypeScript的強制類型聲明語法
這裡可以使用ts的強制類型聲明語法 <TYPE>
,來把指定類型強制聲明為其他類型,如下:
var a;
(<string>a).charAt(0);//合法
(<number>a).toFixed();//合法
強制類型聲明的局限性
但是此語法也有局限性,即只能強制聲明那些未知類型的變數,不能強制聲明已知類型的變數,如下:
var a = 0;
(<string>a);//報錯 Neither type 'number' nor type 'string' is assignable to the other.
因為變數a已經可以被類型推斷出為number
類型了,遂不能再強制聲明為string
類型。
計算屬性類型的解決方案
解決方案為 利用any
類型中轉來實現強制類型聲明轉換。
在TypeScript中的any
類型的規則為:
1、任何類型都可以被轉換為
any
類型。
2、any
類型可以轉換為任何類型。
所以先將計算屬性的函數,或是getter,setter的Object聲明為any
類型,再聲明為你想實際使用的變數類型。如下:
declare var VM: vuejs.Vue & typeof vmComputed;
var vmComputed = {
/**
* 字元串計算屬性
*/
xxcanghaiCom: <string>(<any>function () {
return "xxcanghaiCom";
}),
/**
* getter和setter形式的字元串計算屬性
*/
xxcanghaiGetSet: <string>(<any>{
get: function () {
return vm.xxcanghaiCom;
},
set: function (newVal: string) {
vm.xxcanghaiCom = newVal;
}
})
}
var vm: typeof VM = <any>new Vue({
el: "#app",
computed: <any>vmComputed
});
效果如下圖,雖然xxcanghaiGetSet
是object,但此處可以按照我們想要的string
類型來使用。

後記
本文比較初級,因為剛剛開始接觸Vue,因為之前用過Angular和Avalon,所以上手起來還算舒服,之前用Angular的時候就因為用TypeScript寫非常難受,遂打算好好研究下TypeScript與Vue的協同工作的問題。
寫的比較匆忙,vue也還沒有完全瞭解,遂文中有不對的地方歡迎指正。:-)