網站首頁 編程語言 正文
正文
TypeScript 是微軟于 2012 年推出的一門語言,它是 JavaScript 的超集,具有更強的可選類型系統。TypeScript 和 JavaScript 一樣是有嚴格模式的,今天就來看看 TypeScript 中的嚴格模式如何開啟,以及它到底有多嚴格!
TypeScript 的配置項都寫在項目根目錄名為 tsconfig.json
的配置文件中,可以通過以下方式來開啟嚴格模式:
{ ... "compilerOptions": { "strict": true, ... }, ... }
TypeScript 編譯器有超過 90 個不同的配置項。其中 7 個是關于嚴格模式的:
- noImplicitAny
- noImplicitThis
- alwaysStrict
- strictBindCallApply
- strictNullChecks
- strictPropertyInitialization
- strictFunctionTypes
當在 tsconfig.json
中開啟嚴格模式之后,就相當于開啟了這些配置:
{ ... "compilerOptions": { "noImplicitAny": true, "noImplicitThis": true, "alwaysStrict": true, "strictBindCallApply": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictPropertyInitialization": true, ... } ... }
下面就來分別看一下這些選項都有什么含義。
noImplicitAny
此規則不允許變量或函數參數具有隱式 any
類型。來看下面的例子:
const add10 = number => number + 10;
當啟用了嚴格模式時,函數參數 number 就報錯了:
參數“number”隱式具有“any”類型。ts(7006)
要想修復這個報錯,只需給參數或變量顯式指定類型:
const add10 = (number: number) => number + 10;
因此 noImplicitAny 規則可以確保代碼更具可讀性。否則,add10
函數的調用者需要推斷參數是一個數字,那使用 TypeScript 還有什么意義呢?
noImplicitThis
此規則不允許 this
隱式定義上下文。來看下面的例子:
class Person { weight: number; height: number; constructor(weight: number, height: number) { this.weight = weight; this.height = height; } getBodyMassIndex() { return function () { return this.weight / (this.height * this.height); }; } }
當啟用了嚴格模式時,getBodyMassIndex
中的 this
就報錯了:
"this" 隱式具有類型 "any",因為它沒有類型注釋。ts(2683)
解決這個問題的方法就是使用箭頭函數,因為箭頭函數使用其父級的執行上下文:
class Person { weight: number; height: number; constructor(weight: number, height: number) { this.weight = weight; this.height = height; } getBodyMassIndex() { return () => { return this.weight / (this.height * this.height); }; } }
alwaysStrict
此規則指定始終以嚴格模式檢查每個模塊,并且在編譯之后的 JavaScript 文件中加入"use strict",用來告訴瀏覽器該 JavaScript 為嚴格模式。
ECMAScript 嚴格模式是在 ES5 中引入的,它只是向編譯器提示代碼應該以嚴格模式執行,使用嚴格模式可以使代碼更以更安全、高效的方式運行。
strictBindCallApply
此規則可以確保使用具有正確參數的 call()
、bind()
和 apply()
函數。來看下面的例子:
const logNumber = (x: number) => { console.log(`number:${x}`) } logNumber.call(undefined, "10"); //
當啟用了嚴格模式時,getBodyMassIndex
中的 this
就報錯了:
類型“string”的參數不能賦給類型“number”的參數。ts(2345)
當遇到這種報錯時,只需檢查函數調用的參數,并使用正常的方式調用:
logNumber.call(undefined, 10); // number:10
strictNullChecks
此規則使得 null和 undefined 值不能賦值給非這兩種類型的值,別的類型的值也不能賦給它們。除了 any 類型,還有個例外就是 undefined 可以賦值給 void 類型。這個選項可以幫助 Uncaught TypeError 錯誤。來看下面的例子:
interface Book { name: string; author: string; } const books: Book[] = [ {name: 'Test1', author: 'Max'} ]; const getBookByAuthor = (author: string) => books.find((book) => book.author = author); const book = getBookByAuthor("John"); console.log(book.name);
當啟用了嚴格模式時,打印 book.name
時就報錯了:
對象可能為“未定義”。ts(2532)
如果未開啟嚴格模式,即使 book.name
可能未定義,此代碼也會編譯。想要修復這個問題,就需要為要編譯的代碼添加 null 檢查:
interface Book { name: string; author: string; } const books: Book[] = [ {name: 'Test1', author: 'Max'} ]; const getBookByAuthor = (author: string) => books.find((book) => book.author = author); const book = getBookByAuthor("John"); if (book) { console.log(book.name); } else { console.log('Book not found'); }
函數中也是一樣的,來看下面的例子:
interface Book { name: string; author: string; } const books: Book[] = [ {name: 'Test1', author: 'Max'} ]; const getBookByAuthor = (author: string) => books.find((book) => book.author = author); const book = getBookByAuthor("John"); const logBookName = (book: Book) => { console.log(book.name); } logBookName(book);
如果啟用了嚴格模式時,調用 logBookName(book);
時就會報錯:
類型“Book | undefined”的參數不能賦給類型“Book”的參數。
? 不能將類型“undefined”分配給類型“Book”。ts(2345)
這里提供兩種解決方案:
-
A:將
logBookName
函數參數類型設置為Book | undefined
-
B:
null
檢查條件調用
// A const logBookName = (book: Book | undefined) => { if (book) { console.log(book.name); } else { console.log('not book'); } } // B if (book) { logBookName(book); }
使用該規則時,可以強制開發人員編寫具有更好類型描述的代碼。
strictPropertyInitialization
此規則將強制在構造函數中初始化所有屬性值。來看下面的例子:
class User { name: string; age: number; occupation: string | undefined; constructor(name: string) { this.name = name; } }
在上面的代碼塊中有一個 User
類,constructor()
方法是初始化其實例屬性的地方。當實例化一個類對象時,JavaScript 會自動調用 constructor()
方法。Typescript 要求要么初始化定義的屬性,要么指定一個 undefined
類型。因此,當編譯上面的代碼時,將會提示以下錯誤:
屬性“age”沒有初始化表達式,且未在構造函數中明確賦值。ts(2564)
對于上面的代碼,可以這樣改:
// A:指定 undefined 類型 class User { name: string; age: number | undefined; occupation: string | undefined; constructor(name: string) { this.name = name; } } // B:初始化定義的屬性 class User { name: string; age: number; occupation: string | undefined; constructor(name: string, age: number) { this.name = name; this.age = age; } }
strictFunctionTypes
此規則會更徹底地檢查函數參數。Typescript 參數默認是雙向協變的,這意味著它們既可以是協變的,也可以是逆變的。方差是一種深入了解子類型關系的方法。當參數是協方差時,我們可以將特定類型分配給更廣泛的類型(例如將子類型分配給超類型)。逆變是相反的:可以將更廣泛的類型分配給特定類型(例如將超類型分配給子類型)。
// 非嚴格模式 interface Animal { name: string; } interface Dog extends Animal { breeds: Array<string>; } let getDogName = (dog: Dog) => dog.name; let getAnimalName = (animal: Animal) => animal.name; getDogName = getAnimalName; // Ok getAnimalName = getDogName; // Ok
上面的代碼運行時并沒有提示錯誤,默認情況下參數是雙向協變比較的。超類型 getAnimalName
和子類型 getDogName
的方法可以相互分配。當開啟嚴格模式之后,則 TypeScript 的參數進行逆變比較。
// 嚴格模式 interface Animal { name: string; } interface Dog extends Animal { breeds: Array<string>; } let getDogName = (dog: Dog) => dog.name; let getAnimalName = (animal: Animal) => animal.name; getDogName = getAnimalName; // Ok getAnimalName = getDogName; // Error
當開啟嚴格模式時,最后一行將報以下錯誤:
不能將類型“(dog: Dog) => string”分配給類型“(animal: Animal) => string”。
? 參數“dog”和“animal” 的類型不兼容。
? ? 類型 "Animal" 中缺少屬性 "breeds",但類型 "Dog" 中需要該屬性。ts(2322)
這里,getAnimalName
是比 getDogName
更廣泛的函數。因此,在這種情況下,無法將超類型分配給子類型。但是,可以將子類型分配給超類型。大多數時候,函數參數應該是逆變的,而不是雙向協變的。如果開啟嚴格模式,Typescript 將不會將函數參數視為雙向協變。
原文鏈接:https://juejin.cn/post/7193880226814754875
相關推薦
- 2022-05-14 Python偽隨機數模塊random詳解_python
- 2022-12-27 一文帶你了解Go語言標準庫strings的常用函數和方法_Golang
- 2022-05-17 springboot打包為jar
- 2022-09-09 C++中vector<vector<int>?>的基本使用方法_C 語言
- 2022-07-30 注冊中心eureka的介紹及源碼探索
- 2022-05-14 詳解react-router-dom?v6版本基本使用介紹_React
- 2022-11-17 啟動VMware時遇到“vmx86版本不匹配問題”的完美處理方法_VMware
- 2022-12-03 SQL?Server如何通過SQL語句直接操作另一臺服務器上的SQL?SERVER的數據_MsSql
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支