不用typsescript也能使用型別增強功能

小云菜發表於2021-03-04

由於 JS 的弱型別、寬鬆的編寫規範、以及開發工具的弱雞支援,我們在維護前人的程式碼時,經常會出現不知道某一個方法或欄位命名來自於哪裡,一定要在全域性搜尋以後慢慢篩查才能找到

同樣我們在使用介面返回的物件欄位時,也不知其型別幾何,意思幾何

甚至在我們使用掛載到 vue 全域性物件上的方法時,純粹靠猜,尤其是當函式可以接收多種型別的時候,很痛苦

先說目的:我們希望一切資源皆可索引到其定義或來源,可以有程式碼補全,在vscodectr+滑鼠左鍵皆可導航到,提高效率,用的爽

具體配置資訊

配置全域性jsconfig.json

我們習慣在wepback內配置相關路徑別名,為了讓vscode識別,我們需要做如下配置

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "exclude": ["node_modules", "dist"],
  "include": ["src/**/*", "global.d.ts"]
}

安裝外掛vue-helper

安裝該外掛是為了解決vscode-intelligence不識別.vue檔案,進而無法導航的問題

不過依然存在bug,如果import x變數名不和file-name相同,則無法識別。

終極解決方案是對 .vue檔案進行js託管

export { default } from './index.vue'

vscode可以一步完美導航到具體頁面

討厭寫重複程式碼?定義個 snippet

  "export default": {
    "scope": "javascript,typescript",
    "prefix": "expd",

    "body": ["export {default} from './index.vue${1}';"]
  },
  "export default as": {
    "scope": "javascript,typescript",
    "prefix": "expdas",

    "body": ["export {default as ${2}} from './index.vue${1}';"]
  },

為掛在到Vue上的方法或屬性新增型別宣告

根目錄下新建global.d.ts, 並新增至jsconfig.json: include

// global.d.ts
import Vue from 'vue'
type FnVoid = (...ags: any[]) => void

declare module '*.vue' {
  export default Vue
}
declare module 'vue/types/vue' {
  interface Vue {
    $$title: (title: string) => void
    $$login: FnVoid
    // ......
  }
}

寫正確的註釋

vscode現今對 jsdoc語法的支援愈發完善,在程式碼編寫程式碼階段可以給我們強大的程式碼提示程式碼補全以及程式碼檢查

比如我們可以在註釋內定義變數,針對列表返回的介面,且不需要定義 model 物件來承接資料的話,自定義變數就很有用了

甚至於還支援import語法

不過,不依附於方法之上的註釋變數是不可用的
比如我新建一個檔案,並寫入以下注釋

/**
 * @typedef {Object}  person
 * @property {string} name
 * @property {number} age
 */

在程式碼內是無法引用的

/**@type import('./test').person */

我覺得都已經到了抽象物件多處複用的地步了,為什麼不直接在model層下新建物件呢

估計vscode也是基於此考慮的

另外物件如果是通過計算得來的,vscode 程式碼提示功能也無法識別

如下程式碼是不能針對物件屬性進行提示的

我們在編寫程式碼中儘量避免這種寫法

const func = () => {
  return ['a', 'b', 'c'].reduce((pre, cur) => {
    pre[cur] = 'hello ' + cur
    return pre
  }, {})
}

let obj = func()

Advanced

如果我們想在程式碼中對事件定義新增提示怎麼辦呢?
比如我註冊了一個事件

test.on('handleInputClicked', () => {})

很遺憾,目前在jsdoc上還做不到

可喜的是,在最新發布的ts4.1.beta上增加了對型別模板字串的支援

基於此,我們甚至可以實現對 vuex 的支援

具體的文件參見TypeScript 4.1 型別模板字串實現 Vuex 的 store.commit 和 store.dispatch 型別判斷

相關文章