React TSLint中常見的問題及處理方法

genetalks_大資料發表於2019-04-04

本文中很多地方會用ts表示typescript。本文主要針對剛使用typescript和tslint的同學,新手使用TSLint規則校驗typescript程式碼時,總會碰到一些TSLint的錯誤提示,花費較多的時間和精力去解決這些錯誤資訊,本篇文章將列出本人在專案開發中使用TSLint碰到的問題,及解決方案。TSLint是可配置的,如果專案中引用了TSLint,會有一個tslint.json的配置檔案,可以通過其中的配置項去選擇需要校驗的規則,不知道如何配置的同學可以訪問: [link]: palantir.github.io/tslint/rule… 網上也有很多關於配置的文章。 宣告:本文中TSLint的提示資訊為本次專案中tslint.json所配置的校驗規則。

宣告、匯入

當我們在使用React + js 時,宣告一個變數、宣告一個函式、匯入一個模組等等,宣告或匯入後沒有使用,也不會報錯。程式也能正常執行。但在ts中宣告瞭就需要去使用,不然就會。。。

舉個例子,本文會重複使用這個例子作為參考

這裡是第一個例子,本人用截圖的方式把程式碼和錯誤提示展示出來,後面的錯誤提示或者執行時的錯誤資訊,會在例子的下面標註出來,會在例子的下面標註出來,會在例子的下面標註出來。好了,重要的事情說三遍。

React TSLint中常見的問題及處理方法

從上圖中可以看出,錯誤提示很明顯,IConfig宣告瞭但沒有引用。宣告變數、宣告函式、匯入模組等,宣告或匯入後沒有引用就會有上圖這樣的錯誤提示,或者執行時會有大概一下幾種錯誤提示:

  1. '***' is declared but its value is never read.
  2. 'IConfig' is declared but never used.
  3. All imports in import declaration are unused.

總之碰到這些型別錯誤的時候還是很好解決的,我們去使用它不就得了。還是上面的這個例子,作為第一個解決方案,我們也使用截圖。。。

React TSLint中常見的問題及處理方法

這時就沒有錯誤提示啦,是不是很開心。。。故事當然不會這麼快就結束。執行時出現了這個錯誤:An empty interface is equivalent to {}.因為我們在tslint.json中設定了"no-empty-interface":true,我們需要這樣做:

import React from 'react';
interface IConfig {
  orgName: 'bwa'
}
class Test extends React.Component<IConfig> {
  public render() {
    return (
      <div />
    );
  }
}
export default Test;
複製程式碼

宣告的錯誤型別暫時到這裡到這裡,上面的程式碼已經可以正常執行。

tslint這樣處理的優點

  1. 避免了不必要的變數宣告,及減少了從未使用到的殭屍程式碼。
  2. 避免了不必要的匯入模組、函式,使整個專案更加輕量級。
  3. 可讀性更高。

匯入一個介面或一個方法時tslint的提示

現在我們的編輯器都相當的智慧,本人使用的是VSCode,把滑鼠移到方法上面就會有他的使用方式。

例子:

import React from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
interface IConfig {
  orgName: 'bwa';
}
class Test extends React.Component<IConfig & RouteComponentProps<>> {
  public render() {
    return (
      <div />
    );
  }
}
export default Test;
複製程式碼

上面的程式碼在使用RouteComponentProps這個路由介面時tslint會有:Generic type 'RouteComponentProps<P, C>' requires between 1 and 2 type arguments. RouteComponentProps需要1~2個引數。我們只需要改動:

class Test extends React.Component<IConfig | RouteComponentProps<{name: gtx}>> {}
複製程式碼

{name: gtx}裡的name表示路由上的'/files/data/:name'。

滑鼠放在withRouter上時,提示他是一個函式,它繼承了RouteComponentProps介面,它有一個引數,並且這個引數的型別是元件型別,這個方法返回的是一個元件,這個元件擁有了RouteComponentProps裡面定義的引數。

用法:

export default withRouterTest(Test);
複製程式碼

tslint這樣處理的優點

  1. tslint較為直觀的提示我們介面、方法應該怎樣使用,需要的引數型別。
  2. 不需要編譯就能知道錯誤的準確位置,更正方法。

物件的鍵排序,這裡使用的是按字母的順序排序

class Test extends React.Component<IConfig & RouteComponentProps<{ name: 'gtx' }>> {
  public state: {
    age: number;
    sex: string;
  } = {
      sex: '男',
      age: 18,
    };
  public render() {
    return (
      <div />
    );
  }
}
複製程式碼

這是我們編譯時,瀏覽器會提示:The key 'age' is not sorted alphabetically 需要按字母順序排序。關於鍵需要按字母順序排序之類的問題,很好理解我們就不多說了。

{
  age: 18,
  sex: '男',
};
複製程式碼

當兩個物件的鍵比較多且要求相等,我們有時會落下其中的某個鍵,如果不是按一定規則排序的話就會非常難尋找。

tslint這樣處理的優點

  1. 容易比對出是什麼地方落下的某個鍵,(小技巧:按字母排序的話,比對同一個字母開頭的鍵的開始行與結束行?);

型別問題

import React from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
interface IConfig {
  orgName: 'bwa';
}
interface IData {
  data: IConfig[]
};
class Test extends React.Component<IConfig & RouteComponentProps<{ name: 'gtx' }>> {
  public state: {
    age: number;
    sex: string;
    results: IData;
  } = {
      age: 18,
      sex: '男',
    };
  public render() {
    return (
      <div />
    );
  }
}
export default withRouter(Test);
複製程式碼

這時我們的state會報:Type '{ sex: string; age: number; }' is not assignable to type '{ age: number; sex: string; results: IData; }'. Property 'results' is missing in type '{ sex: string; age: number; }'. 型別XXX不能賦給型別XXX ,仔細看裡面的提示理會發現沒有給state裡面的鍵results賦值。好吧,根據提示我們來給他賦值

 public state: {
  age: number;
  results: IData;
  sex: string;
} = {
    age: 18,
    results: {
      data: []
    },
    sex: '男',
  };
複製程式碼

看到這裡你可能會說如果鍵的型別有多種吶,並且tslint.json中設定了no-any,那我怎麼宣告鍵的型別吶?嗯,往下看

  public state: {
  age: number;
  hobby: number | string | string[] | IData[] | IData;
  results: IData;
  sex: string;

} = {
    age: 18,
    hobby: 1 || '男' || {data: 'data'},
    results: {
      data: []
    },
    sex: '男',
  };
複製程式碼

1 || '男' || {data: 'data'} 中任何一種都可以賦值給hobby,只寫其中一個也是可以的。

tslint這樣處理的優點

  1. 當我們指定了型別,它就只能是這種型別,這樣的定義,強型別的變數、引數寫出來的程式碼更加的嚴謹,後期的維護更加的方便。
  2. 可讀性更高。

宣告變數與元件的名字一樣或與引入元件的名字一樣時

class Test extends React.Component {
 public child = () => {
   const Test = <hr />;
   return (
     Test
   );
 }
 public render() {
   return (
     <div>
       {this.child()}
     </div>
   );
 }
}
複製程式碼

錯誤提示: Shadowed name: 'Test',此時我們只需要重新宣告變數的名字如const Test -->const hr;

tslint這樣處理的優點

  1. 避免了作用域的混淆(宣告變數與元件的名字一樣或與引入元件的名字一樣,呼叫時很容易出錯,往往這樣的錯誤讓人很頭疼)。
  2. 對開發者更加的友好(不用憑記憶去衡量模組命名是否已佔用了這個變數名)。

console列印資訊

在js中我們常用console列印一些資訊在控制檯,在tslin中很多時候會禁用掉console

tslint.json---> no-console: true; 這時你使用console.log的話就會:Calls to 'console.log' are not allowed.

如何解決呢?

import debug from 'debug';
const log = debug('Component:Test');
複製程式碼

這時我們需要列印資訊時呼叫log('想列印的內容');同時在chrome瀏覽器 -->開發者模式 --> Application --> Local Storage 裡新增: Key: debug, Value: Component:Test,這時我們就能列印出想列印的內容。

如圖

React TSLint中常見的問題及處理方法

這樣做的優點:

  1. 定義了是哪個元件下列印的內容 :Component:Test 這裡是Test下的
  2. Local Storage 裡設定了需要接收的元件,這樣的好處在於,我們在程式碼裡寫了log,但不需要去清除,其他電腦訪問相同頁面時控制檯也會很乾淨,不會列印出這些資訊。
  3. 不同元件下的log資訊會以不同的顏色區分。

本篇文章暫時就到這裡。


作者資訊:寧文飛,人和未來大資料前端工程師

相關文章