優雅地使用TypeScript開發React Native應用

俊寧發表於2019-05-13

React Native 0.57 版本開始,我們終於可以直接使用 TypeScript 開發,不需要任何額外的配置。本文主要介紹如何使用 TypeScript 優雅地開發 React Native 應用。

初始化專案

初始化專案之前,請確保已經按照 React Native 中文網 的搭建開發環境文件完成了環境搭建

$ react-native init AwesomeProject
複製程式碼

注意: 入口檔案 index.js 需要保留,其他檔案都可以使用 .ts.tsx 字尾。

TypeScript編譯器

$ yarn global add typescript
$ yarn add -D typescript
複製程式碼

配置 tsconfig.json

$ tsc --init --pretty --target esnext --allowJs --checkJs --jsx react-native --allowSyntheticDefaultImports --experimentalDecorators --emitDecoratorMetadata
複製程式碼

注意:注意多餘的註釋可能會不相容,需要移除,詳細文件可查閱 編譯選項

配置檔案

tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "allowJs": true,
    "checkJs": true,
    "jsx": "react-native",
    "strict": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "exclude": ["node_modules"]
}
複製程式碼

解釋:

  • target: 指定ECMAScript目標版本 "ES3"(預設),"ES5","ES6"/"ES2015","ES2016","ES2017","ES2018", "ES2019" 或 "ESNext"。
  • module: 指定生成哪個模組系統程式碼:"None","CommonJS","AMD","System","UMD","ES6", "ES2015" 或 "ESNext"。
  • allowJs: 允許編譯javascript檔案。
  • checkJs: 在 .js 檔案中報告錯誤。與 --allowJs 配合使用。
  • jsx: 在 .tsx檔案裡支援JSX: "react"、"react-native"或 "preserve"。檢視 JSX
  • strict: 啟用所有嚴格型別檢查選項。啟用 --strict 相當於啟用 --noImplicitAny, --noImplicitThis, --alwaysStrict--strictNullChecks--strictFunctionTypes--strictPropertyInitialization
  • allowSyntheticDefaultImports: 允許從沒有設定預設匯出的模組中預設匯入。這並不影響程式碼的輸出,僅為了型別檢查。
  • esModuleInterop: TypeScript與Babel採取了不同的方案,並且直到現在,還沒出現真正地固定標準。 簡單地說,如果你使用Babel,Webpack或React Native,並期望與你以往使用地不同的匯入行為,TypeScript提供了該編譯選項。
  • experimentalDecorators: 啟用實驗性的ES裝飾器。
  • 給原始碼裡的裝飾器宣告加上設計型別後設資料。: 給原始碼裡的裝飾器宣告加上設計型別後設資料。

@types/react、@types/react-native

為了提高開發效率和避免 typescript 型別檢查報錯,你需要新增這兩個型別宣告庫。

$ yarn add @types/react @types/react-native -D
複製程式碼

EsLint 程式碼檢測

Lint工具用於檢查程式碼的語法是否正確、風格是否符合要求。最新的工具ESLint不僅允許你自定義語法規則,還允許使用者創造外掛,改變預設的JavaScript語法,比如支援ES6和JSX的語法。

VsCode 支援

安裝 ESLint Plugin

優雅地使用TypeScript開發React Native應用

配置 ESLint Plugin

  • eslint.validate:ESLint 外掛預設只校驗 javascript 和 javascriptreact,所以需要手動開啟其他語言的校驗支援
  • eslint.autoFixOnSave: 開啟儲存時自動修復錯誤
settings.json
{
    "eslint.validate": [
          "javascript",
          "javascriptreact",
          {
              "language": "typescript",
              "autoFix": true
          },
          {
              "language": "typescriptreact",
              "autoFix": true
          },
          {
              "language": "vue",
              "autoFix": true
          },
          {
              "language": "html",
              "autoFix": true
          }
    ],
    "eslint.autoFixOnSave": true,
}
複製程式碼

專案配置

注意:配置之前請確保根目錄下存在 .eslintrc.js。如果要指定忽略某些檔案,可以使用 .eslintignore 檔案(node_modules、bower_compnents 資料夾已經預設被忽略)

$ yarn add -D eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react eslint-plugin-react-native @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-import-resolver-typescript
複製程式碼

配置檔案

.eslintrc.js
module.exports = {
  env: {
    es6: true,
    node: true,
    jest: true,
    'react-native/react-native': true,
  },
  extends: [
    'airbnb',
    'plugin:react-native/all',
    'plugin:@typescript-eslint/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
      impliedStrict: true,
    },
    ecmaVersion: 2018,
    project: './tsconfig.json',
    sourceType: 'module',
  },
  plugins: [
    'import',
    'react',
    'react-native'
  ],
  settings: {
    'import/resolver': {
      typescript: {},
    },
  },
  rules: {
    'global-require': 0,
    'linebreak-style': [2, 'unix'],
    'no-console': [
      'error',
      {
        allow: ['warn', 'error', 'info', 'log'],
      },
    ],
    'lines-between-class-members': [
      2,
      'always',
      {
        exceptAfterSingleLine: true,
      },
    ],
    'no-use-before-define': [
      2,
      {
        functions: true,
        classes: true,
        variables: false,
      },
    ],
    'prefer-destructuring': [
      2,
      {
        array: false,
        object: true,
      },
    ],
    'react/prefer-stateless-function': 0,
    'react/prop-types': 0,
    'react/jsx-filename-extension': [
      2,
      {
        extensions: ['.js', '.jsx', '.tsx'],
      },
    ],
    'jsx-a11y/accessible-emoji': 0,
    'react-native/no-color-literals': 0,
    '@typescript-eslint/no-use-before-define': [
      2,
      {
        functions: true,
        classes: true,
        variables: false,
      },
    ],
    '@typescript-eslint/explicit-function-return-type': {
      allowExpressions: true,
      allowTypedFunctionExpressions: true,
    },
  },
}
複製程式碼
.eslintignore
# /node_modules/* and /bower_components/* ignored by default
複製程式碼

Prettier 程式碼格式化

ESLint 能夠檢測出程式碼中的潛在問題,提高程式碼質量,但是並不能完全統一程式碼風格。而 Prettier 在格式化程式碼方面具有更大優勢。Prettier 掃描檔案中的樣式問題,並自動重新格式化程式碼,以確保縮排、間距、分號、單引號和雙引號等遵循一致的規則。

VsCode 支援

如果你只是想要格式化你的 JS 或 TS 程式碼,你可以忽略這一部分

安裝 Prettier Plugin

優雅地使用TypeScript開發React Native應用

配置 Prettier Plugin

注意:除了以下配置,建議你把其他格式化外掛,比如 beautify 直接解除安裝,並配置 prettier 為預設格式化程式。

  • prettier.requireConfig: 需要專案中存在一個 prettierconfig 檔案才能執行prettier
  • editor.formatOnSave: 開啟儲存時自動格式化
{
    "prettier.requireConfig": true,
    "editor.formatOnSave": true,
}
複製程式碼

規則配置

優雅地使用TypeScript開發React Native應用

Prettier ❤ ESLint

完成上一部分 VSCode 的支援,再配置一個 PrettierConfig 檔案你就可以使用 Prettier 的功能了。但是當樣式出問題時,編輯器並不會給你報錯。更糟糕的是,ESLint 和 Prettier 在格式化規則方面存在一些衝突。幸運的是,Prettier 被設計為易於與 ESLint 整合,所以你可以輕鬆在專案中使兩者,而無需擔心衝突。

$ yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
複製程式碼

配置檔案

.eslintrc.js
module.exports = {
  extends: [
    'prettier',
    'plugin:prettier/recommended',
    'prettier/react',
    'prettier/@typescript-eslint',
  ],
}
複製程式碼
.eslintignore
# /node_modules/* and /bower_components/* ignored by default
複製程式碼
.prettierrc.js
module.exports = {
  semi: false, // 行位是否使用分號,預設為true
  trailingComma: 'es5', // 是否使用尾逗號,有三個可選值"<none|es5|all>"
  singleQuote: true, // 字串是否使用單引號,預設為false,使用雙引號
  printWidth: 120, // 一行的字元數,如果超過會進行換行,預設為80
  tabWidth: 2, // 一個tab代表幾個空格數
  bracketSpacing: true, // 物件大括號直接是否有空格,預設為true,效果:{ foo: bar }
}
複製程式碼
.prettierinore
**/node_modules/*
src/**/*.js
src/**/*.jsx
src/**/*.ts
src/**/*.tsx
複製程式碼

EditorConfig 跨編輯器配置統一

當多人共同開發一個專案的時候,往往會出現大家用不同編輯器的情況。就前端開發者來說,有人喜歡 Sublime,有人喜歡 Webstorm , 也有人喜歡 Atom,還有人喜歡 Vim,HBuilder 等等。各種不同程式語言的開發者喜歡各種不同的編輯器。EditorConfig 這個專案就是為了解決跨編輯器開發專案的程式碼風格統一問題的。

VSCode Plugin

安裝

安裝完後不需要配置,直接在專案中新增配置檔案即可。

優雅地使用TypeScript開發React Native應用

配置檔案

.editorconfig
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.gradle]
indent_size = 4

[BUCK]
indent_size = 4
複製程式碼

Git pre-commit Hook

pre-commit鉤子在鍵入提交資訊前執行。 它用於檢查即將提交的快照,例如,檢查是否有所遺漏,確保測試執行,以及核查程式碼。 如果該鉤子以非零值退出,Git 將放棄此次提交,不過你可以用git commit --no-verify來繞過這個環節。 你可以利用該鉤子,來檢查程式碼風格是否一致(執行類似 lint 的程式)、尾隨空白字元是否存在(自帶的鉤子就是這麼做的),或新方法的文件是否適當。

husky: 輕鬆使用 Git hooks

Husky 能阻止壞的 git commit, git push 和更多的?

$ yarn add -D husky
複製程式碼

配置檔案

.huskyrc.js
module.exports = {
  hooks: {
    'pre-commit': 'node node_modules/eslint/bin/eslint.js --fix src/**/*.js',
  },
}
複製程式碼

注意:測試發現直接執行 eslint --fix 使用的是全域性的模組。

只使用 husky 的問題

  • 效能問題:對整個專案執行一個lint程式很慢,而且linting結果可能無關緊要。
  • 效率問題:遺留程式碼倉庫上工作的同學很快會遇到新的問題,開啟 Lint 初期,你可能會面臨成千上萬的 Lint Error 需要修復。部分同學對下面這個圖可能並不陌生:只改了檔案 A,但是檔案 B、C、D 中也有大量錯誤。

lint-staged: husky的好幫手

針對暫存的git檔案執行linters並且不要讓?滑入你的程式碼庫!對暫存區概念不熟悉的同學可以看下git-簡明指南

$ yarn add -D husky lint-staged
複製程式碼
  • husky: 被用來新增一些 git 鉤子,這裡我們需要一個用 pre-commit 在每次 git commit 操作時執行 lint-staged 命令。
  • lint-staged: 可以對 git 暫存區檔案(也就是你想要 commit 的檔案)執行一些操作,這樣做即提高了效能又提高了效率。

配置檔案

.huskyrc.js
module.exports = {
  hooks: {
    'pre-commit': 'lint-staged',
  },
}
複製程式碼
lint-staged.config.js
module.exports = {
  "src/**/*.{js,jsx,ts,tsx}": ["eslint --fix", "git add"]
}
複製程式碼

相對於根目錄引入元件

這部分不是必須的,配置也有些繁瑣。這裡我就只介紹下簡單的配置,詳細文件請請查閱 babel-plugin-root-import

安裝

$ yarn add -D babel-plugin-root-import eslint-import-resolver-babel-plugin-root-import
複製程式碼

babel.config.js

module.exports = {
  ...
  plugins: [
    [
      'babel-plugin-root-import',
      {
        rootPathSuffix: 'src',
        rootPathPrefix: '~',
      },
    ],
  ],
  ...
}
複製程式碼

.eslintrc.js

{
  settings: {
    'import/resolver': {
      'babel-plugin-root-import': {
        rootPathSuffix: 'src',
        rootPathPrefix: '~',
      },
    },
  },
}
複製程式碼

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/*": ["src/*"]
    }
  }
}
複製程式碼

支援 .jsx

React Native 都已經內建支援 TypeScript 了,但是卻不支援 .jsx 檔案字尾。如果你想要使用 .jsx 開發,可以配置 metro.config.js:

module.exports = {
  resolver: {
    sourceExts: ['ts', 'tsx', 'js', 'jsx', 'json', 'mjs']
  },
}
複製程式碼

相關資料

相關文章