本文中很多地方會用ts表示typescript。本文主要針對剛使用typescript和tslint的同學,新手使用TSLint規則校驗typescript程式碼時,總會碰到一些TSLint的錯誤提示,花費較多的時間和精力去解決這些錯誤資訊,本篇文章將列出本人在專案開發中使用TSLint碰到的問題,及解決方案。TSLint是可配置的,如果專案中引用了TSLint,會有一個tslint.json的配置檔案,可以通過其中的配置項去選擇需要校驗的規則,不知道如何配置的同學可以訪問: [link]: palantir.github.io/tslint/rule… 網上也有很多關於配置的文章。 宣告:本文中TSLint的提示資訊為本次專案中tslint.json所配置的校驗規則。
宣告、匯入
當我們在使用React + js 時,宣告一個變數、宣告一個函式、匯入一個模組等等,宣告或匯入後沒有使用,也不會報錯。程式也能正常執行。但在ts中宣告瞭就需要去使用,不然就會。。。
舉個例子,本文會重複使用這個例子作為參考
這裡是第一個例子,本人用截圖的方式把程式碼和錯誤提示展示出來,後面的錯誤提示或者執行時的錯誤資訊,會在例子的下面標註出來,會在例子的下面標註出來,會在例子的下面標註出來。好了,重要的事情說三遍。
從上圖中可以看出,錯誤提示很明顯,IConfig宣告瞭但沒有引用。宣告變數、宣告函式、匯入模組等,宣告或匯入後沒有引用就會有上圖這樣的錯誤提示,或者執行時會有大概一下幾種錯誤提示:
- '***' is declared but its value is never read.
- 'IConfig' is declared but never used.
- All imports in import declaration are unused.
總之碰到這些型別錯誤的時候還是很好解決的,我們去使用它不就得了。還是上面的這個例子,作為第一個解決方案,我們也使用截圖。。。
這時就沒有錯誤提示啦,是不是很開心。。。故事當然不會這麼快就結束。執行時出現了這個錯誤: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這樣處理的優點
- 避免了不必要的變數宣告,及減少了從未使用到的殭屍程式碼。
- 避免了不必要的匯入模組、函式,使整個專案更加輕量級。
- 可讀性更高。
匯入一個介面或一個方法時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這樣處理的優點
- tslint較為直觀的提示我們介面、方法應該怎樣使用,需要的引數型別。
- 不需要編譯就能知道錯誤的準確位置,更正方法。
物件的鍵排序,這裡使用的是按字母的順序排序
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這樣處理的優點
- 容易比對出是什麼地方落下的某個鍵,(小技巧:按字母排序的話,比對同一個字母開頭的鍵的開始行與結束行?);
型別問題
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這樣處理的優點
- 當我們指定了型別,它就只能是這種型別,這樣的定義,強型別的變數、引數寫出來的程式碼更加的嚴謹,後期的維護更加的方便。
- 可讀性更高。
宣告變數與元件的名字一樣或與引入元件的名字一樣時
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這樣處理的優點
- 避免了作用域的混淆(宣告變數與元件的名字一樣或與引入元件的名字一樣,呼叫時很容易出錯,往往這樣的錯誤讓人很頭疼)。
- 對開發者更加的友好(不用憑記憶去衡量模組命名是否已佔用了這個變數名)。
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,這時我們就能列印出想列印的內容。
如圖
這樣做的優點:
- 定義了是哪個元件下列印的內容 :Component:Test 這裡是Test下的
- Local Storage 裡設定了需要接收的元件,這樣的好處在於,我們在程式碼裡寫了log,但不需要去清除,其他電腦訪問相同頁面時控制檯也會很乾淨,不會列印出這些資訊。
- 不同元件下的log資訊會以不同的顏色區分。
本篇文章暫時就到這裡。
作者資訊:寧文飛,人和未來大資料前端工程師