class ts 扩展方法_一些让程序保持可扩展的 TypeScript 技巧
我們使用 TypeScript 的理由是,它有助于開發更快更安全的 app。
TypeScript 默認會做很多簡化,這有助于開發者更容易的上手,但從長遠來看,這些簡化也會浪費不少的開發時間。
我們收集了一系列更為嚴格的 TypeScript 編碼規則。只要你習慣一次,將來就會為你省下大量的編碼時間。
any
這是一條很簡單的規則,但長遠看我們可以從中得到大大的好處。
永遠都不要使用 “any”,永遠!!!
原因很簡單,因為不會有任何場景需要使用 “any” 來描述一個類型。如果你遇到了使用 any 的情況,可能是架構、代碼遺留或者其他特殊問題。
使用 泛型,未知類型 或者 重載 然后就不用擔心數據結構上會出現意料之外的問題了。而這類問題的調試成本通常都很高。
嚴格模式
TypeScript 有 “嚴格” 模式,不過遺憾的這個模式默認處于關閉狀態。此模式下有一系列的規則可以讓 TypeScript 用起來更安全舒適。如果不了解此模式,參考 這篇文章。
在 “嚴格” 模式下,你可以完全不用擔心諸如 undefined is not a function、cannot read property X of null 等錯誤。你的類型定義將會無比的準確。
我得怎樣做?
如果你開了一個新項目,享受 “嚴格模式” 的樂趣吧。
如果你有一個非 “嚴格模式” 的項目,然后你還想為此項目開啟嚴格模式,那么你首先看到的就是一堆編譯問題。如果沒有編輯器的警告的話,編寫滿足嚴格模式的代碼是一件非常困難的事情,所以你在打開嚴格模式后很可能會碰到很多有問題的地方。因此遷移整個項目到 “嚴格模式” 很快就能讓人感到煩躁。
對此的建議是將這個大任務切割為小塊兒。“嚴格” 模式由 6 條規則組成。可以啟用其中的一條規則并且修復所有的錯誤。下一次啟用第二條規則,修復錯誤并且循環往復。終有一天會完全遷移到 “嚴格” 模式的。
tsconfig.json 文件
{
// ...,
"compilerOptions": {
// 一組很溜的規則配置
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
// 支持上述六個規則的快捷配置
"strict": true,
// ...
}
}
只讀
對我們 TypeScript 開發者來說,下一個重要的規則是無時無刻使用只讀。
在處理的過程中改變數據結構是一種不好的實踐。舉個栗子,Angular 就不喜歡這種處理方式:當轉換數據時,視圖的變更檢測和視圖更新會出現一些問題。
但你完全可以輕松的阻止所有的數據更改,只要養成寫 readonly 關鍵字的習慣。
我們應該怎么做呢?
應用中有很多地方可以將不安全的類型替換為只讀類型。
在 interface 中使用 “readonly” 屬性
// 之前
export interface Thing {
data: string;
}
// 之后
export interface Thing {
readonly data: string;
}
首選 “readonly” 類型
// 之前
export type UnsafeType = { prop: number };
// 之后
export type SafeType = Readonly; // Prefer “readonly” types
在類中盡可能的使用 “readonly” 字段
// 之前
class UnsafeComponent {
loaderShow$ = new BehaviorSubject(true);
}
// 之后
class SafeComponent {
readonly loaderShow$ = new BehaviorSubject(true);
}
使用 “readonly” 結構
// 之前
const unsafeArray: Array = [1, 2, 3];
const unsafeArrayOtherWay: number[] = [1, 2, 3];
// 之后
const safeArray: ReadonlyArray = [1, 2, 3];
const safeArrayOtherWay: readonly number[] = [1, 2, 3];
// 三種寫法,三種安全等級
const unsafeArray: number[] = [1, 2, 3]; // 糟糕的
const safeArray: readonly number[] = [1, 2, 3]; // 還不錯
const verySafeTuple: readonly [number, number, number] = [1, 2, 3]; // 最棒的
// 映射:
// 之前
const unsafeMap: Map = new Map();
// 之后
const safeMap: ReadonlyMap = new Map();
// 集合:
// 之前
const unsafeSet: Set = new Set();
// 之后
const safeSet: ReadonlySet = new Set();
設為常量
在 TypeScript v.3.4 中我們可以使用 常量斷言 。
這是一個相比 “readonly” 更加嚴格的限制手段,因為它將實例封裝為最準確的類型,你可以理解為沒有任何情況可以改變它的值。
設為常量 后還可以在 IDE 中獲取到準確的類型提示。
實用類型
TypeScript 有一組特殊的類型,這些類型是其他類型的快捷轉換形式。
請查閱 實用類型的官方文檔 并且在 app 中使用他們。這將會為你節約很多時間。
縮小你的類型范圍
TypeScript 有很多工具可以縮小類型范圍。這個特性很有用,因為我們可以在項目中支持各種各樣場景下的嚴格限制的輸入。
看下如下樣例。這是一個很簡單的例子,不過它可以幫助我們理解類型檢查和類型范圍縮小的區別。
import {Subject} from 'rxjs';
import {filter} from 'rxjs/operators';
interface Data {
readonly greeting: string;
}
const data$$ = new Subject();
/**
* source$ 指定了類型 "Observable"
* 然而 "null" 并不能通過此函數過濾器
*
* 這是因為 typescript 不能確定類型是否產生了變化。
* 函數 “value => !!value” 返回了布爾值但是未明確聲明類型
*/
const source$ = data$$.pipe(
filter(value => !!value)
)
/**
* 如下是一些比較好的例子
*
* 箭頭函數返回 “是否為 Data 類型的數據” 的結果
* 它縮小了類型范圍,并使 "wellTypedSource$" 擁有了正確的類型
*/
const wellTypedSource$ = data$$.pipe(
filter((value): value is Data => !!value)
)
// 如下代碼不能被編譯,你可以試下
// source$.subscribe(x => console.log(x.greeting));
wellTypedSource$.subscribe(x => console.log(x.greeting));
data$$.next({ greeting: 'Hi!' });
你可以通過如下方法縮小類型范圍:
**typeof** 來自 Javascript 的操作符,用于檢查原始類型
**instanceof** 來自 Javascript 的操作符,用于檢查被繼承的實例
**is T** TypeScript 的聲明,允許檢查復雜類型以及接口。不過你得小心的使用這個功能,因為確保類型正確是你的責任,而不是 TypeScript 的。
一些使用樣例:
// typeof 限制
function getCheckboxState(value: boolean | null): string {
if (typeof value === 'boolean') {
// value 只能是 "布爾" 類型
return value ? 'checked' : 'not checked';
}
/**
* 在此范圍內,值可能為 “null” 類型
*/
return 'indeterminate';
}
// instanceof 限制
abstract class AbstractButton {
click(): void { }
}
class Button extends AbstractButton {
click(): void { }
}
class IconButton extends AbstractButton {
icon = 'src/icon';
click(): void { }
}
function getButtonIcon(button: AbstractButton): string | null {
/**
* 在 "instanceof" 后 TS 就能知道數據類型是 "icon"
* field
*/
return button instanceof IconButton ? button.icon : null;
}
// is T 限制
interface User {
readonly id: string;
readonly name: string;
}
function isUser(candidate: unknown): candidate is User {
return (
typeof candidate === "object" &&
candidate !== null &&
"id" in candidate &&
"name" in candidate
);
}
const someData = { id: '42', name: 'John' };
if (isUser(someData)) {
/**
* TS 現在知道了 someData 實現了 User 接口
*/
console.log(someData.id, someData.name)
}
總結
特別是在安全且嚴格的 TS 開發過程中,這些技術在團隊中起著很重要的作用。當然,它們也不能解決所有的問題,不過如果你一旦開始使用,這將使你能夠在大型項目中避開一些非預期的棘手的錯誤。
這篇文章是進階 Angular - 大型 Angular 交互手冊的第二章。你可繼續瀏覽 Angular 相關的內容:Angular 研究會
本文中的所有譯文僅用于學習和交流目的,轉載請務必注明文章譯者、出處、和本文鏈接
我們的翻譯工作遵照 CC 協議,如果我們的工作有侵犯到您的權益,請及時聯系我們。
總結
以上是生活随笔為你收集整理的class ts 扩展方法_一些让程序保持可扩展的 TypeScript 技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lbp特征提取算法 知乎_计算机视觉基础
- 下一篇: 多层陶瓷电容器用处_典型陶瓷电容的用途和