本文是繼 Vue + TypeScript 新專案起手式 之後的進階 + 踩坑配置,所以推薦先閱讀前文
完整閱讀完之後,基本可以順利在新專案中使用
vue
+typescript
了另外特別注意!!!
不推薦在已有專案上強加
typescript
, 因ts寫法的元件跟之前的元件不相容,若上的話需要修改之前寫的元件
配置完整版可參考 vue-typescript-starter,若沒配置出來,也可以對照修改配置
直接進入正題:
概覽
ts
支援render jsx
寫法ts
支援es6 / es67
- 配置
vuex
vue
識別全域性方法/變數- 支援
mixin
- 支援
ProvidePlugin
的全域性變數,比如lodash
的_
支援 render jsx 寫法
這裡一共分兩步
- 首先得先讓
vue
支援jsx
寫法 - 再讓
vue
中的ts
支援jsx
寫法
讓 vue 支援 jsx
按照官方做法,安裝Babel 外掛
安裝依賴
npm install\
babel-plugin-syntax-jsx\
babel-plugin-transform-vue-jsx\
babel-helper-vue-jsx-merge-props\
babel-preset-es2015\
--save-dev複製程式碼
在.babelrc
中新增:
{
"plugins": ["transform-vue-jsx"]
}複製程式碼
之後就可以這些寫render
,如下圖:
讓 ts 支援 jsx
首先配置 webpack
找到./build/webpack.base.conf.js
- 找到
resolve.extensions
裡面加上.tsx
字尾
resolve: {
extensions: ['.js', '.vue', '.json', '.ts', '.tsx']
}複製程式碼
- 找到
module.rules
修改webpack對.tsx
.ts
的解析
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
// 從這裡複製下面的程式碼就可以了
// 如果之前按照起手式配置的同學,請替換配置
{
test: /\.tsx?$/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'tslint-loader'
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: Object.assign(vueLoaderConfig, {
loaders: {
ts: "ts-loader",
tsx: "babel-loader!ts-loader"
}
})
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
"babel-loader",
{
loader: "ts-loader",
options: { appendTsxSuffixTo: [/\.vue$/] }
}
]
},
// 複製截止
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},複製程式碼
上面的配置,主要意思是 vue
檔案識別ts/tsx
程式碼的時候,先過一遍ts-loader
,在過一遍babel-loader
,我知道這聽起來有點蠢,但是jsx
不能不要對吧?
然後在 tsconfig.json
中,新增對jsx
的支援
"compilerOptions": {
"jsx": "preserve"
}複製程式碼
之後就可以順利在.vue
單檔案中的ts
寫jsx
程式碼了,如下圖所示:
敲黑板,這裡又有重點,使用
jsx
寫法的話, 一定要使用.tsx
,不要用.ts
了,切記!!!
支援es6 / es7
在 tsconfig.json
中,新增對es6 / es7
的支援,更多的配置請見tsconfig - 編譯選項
"lib": [
"dom",
"es5",
"es6",
"es7",
"es2015.promise"
]複製程式碼
不然的話,連Object.assign
這種最基本的函式也會在ts
中報錯,真的令人難過
配置 vuex
這裡就比較簡單了
# 安裝依賴
npm i vuex vuex-class --save複製程式碼
- vuex:在
vue
中集中管理應用狀態 - vuex-class :在
vue-class-component
寫法中 繫結vuex
Store
的配置跟原來一模一樣,引用的時候有一點區別,下面的例子介紹了用法,應該一看便知,這裡我不做贅述
import Vue from 'vue'
import Component from 'vue-class-component'
import {
State,
Getter,
Action,
Mutation,
namespace
} from 'vuex-class'
const ModuleGetter = namespace('path/to/module', Getter)
@Component
export class MyComp extends Vue {
@State('foo') stateFoo
@State(state => state.bar) stateBar
@Getter('foo') getterFoo
@Action('foo') actionFoo
@Mutation('foo') mutationFoo
@ModuleGetter('foo') moduleGetterFoo
// If the argument is omitted, use the property name
// for each state/getter/action/mutation type
@State foo
@Getter bar
@Action baz
@Mutation qux
created () {
this.stateFoo // -> store.state.foo
this.stateBar // -> store.state.bar
this.getterFoo // -> store.getters.foo
this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true })
this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true })
this.moduleGetterFoo // -> store.getters['path/to/module/foo']
}
}複製程式碼
讓 vue 識別全域性方法/變數
在專案中使用 ui 元件是很正常的操作
比如使用 Element-uI
的 meesage
,用法如下圖:
this.$message({
message: '恭喜你,這是一條成功訊息',
type: 'success'
})複製程式碼
但是在配置了 typescript
之後
那是因為 $message
屬性,並沒有在 vue
例項中宣告
解決辦法也非常簡單,那我們就宣告一下唄
在之前文章中建立的 src/vue-shim.d.ts
檔案中,增加如下程式碼:
// 宣告全域性方法
declare module 'vue/types/vue' {
interface Vue {
$Message: any,
$Modal: any
}
}複製程式碼
這樣,之後再使用this.$message()的話就不會報錯了
支援 mixin
我在vue-property-decorator
裡裡外外找了好幾圈,缺沒有找到mixin
這個修飾器
// 如果全域性mixin,那也太蠢了
Vue.mixin( mixin )複製程式碼
找非常多的 ts + vue
專案,但是沒有找到我理想的mixin
的方式,
那麼就自己進行探索咯,下圖是我自己使用的目前最佳mixin
方式:
宣告瞭一個mixin元件,如下圖:
其實就是我在mixin
中宣告瞭宣告屬性 / 方法,那麼我就在vue
例項中宣告這個屬性 / 方法
使用方式如下圖:
支援 ProvidePlugin 的全域性變數,比如 lodash 的 _
如果我們在專案中有使用 jquery,lodash
這樣的工具庫的時候,肯定不希望在所有用到的地方都import _ from ‘lodash’
@types/lodash
那我們就來配置一下:
首先還是在webpack.base.conf.js
中新增一個外掛、並把這個 vendor
拉出來
entry: {
app: './src/main.ts',
vendor: [
"lodash"
]
}
plugins: [
new webpack.ProvidePlugin({
_: 'lodash'
})
]複製程式碼
上面的意思是,當模組使用這些變數的時候wepback
會自動載入
然後,你需要告訴eslint
這個 _
是全域性的
在.eslintrc.js
中新增
globals: {
_: true
},複製程式碼
接下來,你還需要告訴ts
這個 _
是全域性的
在vue-shim.d.ts
declare global {
const _: typeof lodash
}複製程式碼
如果沒有上面這段宣告,但是在
ts
中使用的話,會報如下的錯誤:
這個問題Consider allowing access to UMD globals from modules · Issue #10178 · Microsoft/TypeScript · GitHub
有一個很簡單的解釋,就是害怕你全域性宣告的_
跟 import _ from 'lodash'
的行為不一致,這樣的話,之後會留下隱患
到這裡,本文的配置就到此結束
最後
本文的這些配置都是在新專案開發中,一步步用血汗踩出來的
目測已經涵蓋了大部分的使用問題,如果有其他的意見或建議的話,歡迎在本文下面評論~~
再發一次,配置完整版可參考 vue-typescript-starter,若沒配置出來,也可以對照修改配置
在剛上typescript
的時候,我是拒絕的,嫌棄每個地方都要宣告型別,不然就走不下去,但是如果讓你們做以下一個選擇題:
- 在編譯時發現問題
- 還是執行時發現問題
我會毫不猶豫選擇前者,這是ts強型別帶給我最大的亮點