強(qiáng)類型與弱類型(類型安全維度)
語(yǔ)言層面限制
- 強(qiáng)類型:不允許任意的數(shù)據(jù)隱式類型轉(zhuǎn)換
- 在編碼階段就能提示類型錯(cuò)誤,可以更早暴露錯(cuò)誤
- 可以提高代碼效率和準(zhǔn)確性(可以提供更準(zhǔn)確的智能提示)
- 使重構(gòu)更便捷可靠
- 可以減少不必要的類型判斷
- 弱類型:允許任意的數(shù)據(jù)隱式類型轉(zhuǎn)換
- 只能在代碼運(yùn)行階段才能發(fā)現(xiàn)問題
- JavaScript是弱類型語(yǔ)言,Python是強(qiáng)類型語(yǔ)言
靜態(tài)類型與動(dòng)態(tài)類型(類型檢查維度)
- 靜態(tài)類型:變量類型在聲明時(shí)確定,之后不允許再修改
- 動(dòng)態(tài)類型:變量在運(yùn)行階段才能確定,且可以進(jìn)行修改
- JavaScript是動(dòng)態(tài)類型語(yǔ)言,Python是動(dòng)態(tài)類型語(yǔ)言
解釋型與編譯型
- 解釋型:代碼運(yùn)行時(shí)解析執(zhí)行(腳本語(yǔ)言)
- 編譯型:需要預(yù)先編譯,再執(zhí)行編譯輸出的可執(zhí)行文件
JavaScript類型系統(tǒng)特征
JavaScript是動(dòng)態(tài)類型 弱類型 解釋型腳本語(yǔ)言
Flow
由Facebook于2014年推出的JavaScript的類型檢查器
-
安裝
yarn add flow-bin --dev-
yarn flow init初始化flow并生成配置文件.flowconfig
-
使用
- 在JS文件開頭添加注釋
//@flow - 在相應(yīng)的變量、參數(shù)后添加類型注解(冒號(hào)及類型)
- 執(zhí)行
yarn flow檢查- 會(huì)啟動(dòng)后臺(tái)服務(wù)監(jiān)控JS文件
- 執(zhí)行
yarn flow stop停止后臺(tái)服務(wù)
- 在JS文件開頭添加注釋
-
編譯移除類型注解
-
flow-remove-types
-
yarn add flow-remove-types --dev安裝 -
yarn flow-remove-types src -d dist指定路徑輸出編譯移除后的JS文件
-
-
babel
yarn add @babel/core @babel/cli @babel/present-flow安裝-
添加配置文件.babelrc
{ "presents": ["@babel/present-flow"] } yarn babel src -d dist指定路徑輸出編譯移除后的JS文件
-
-
開發(fā)工具插件
- VSCode插件:flow-language-support
- 其他IDE插件支持情況查看flow官網(wǎng)的編輯器支持
-
flow類型推斷
- 可以根據(jù)代碼實(shí)際使用情況自行推斷變量的類型,而可以不指明類型注解
-
flow類型注解
- 在相應(yīng)的變量、參數(shù)后添加冒號(hào)及類型
-
flow的類型
- 原始類型
- string
- number
- boolean
- null
- undefined
- 使用void表示
- symbol
- 數(shù)組類型
- Array<number>
- number []
- [string, number] :元組
- 對(duì)象類型
- { foo?: string, bar: number }
- 限制必須存在特定屬性,并限定該屬性的類型
- 屬性名加問號(hào),表示該屬性可選,如果存在該屬性,則屬性類型必須為指定的類型
- { [string]: string }
- 限制對(duì)象key-value鍵值對(duì)類型,不限制屬性數(shù)量
- { foo?: string, bar: number }
- 函數(shù)類型
- (string, number) => void
- 指定參數(shù)及返回值類型
- (string, number) => void
- 特殊類型
- 字面量類型:
a: 'foo' = 'foo'- 限定變量值只能是特定值
- 聯(lián)合類型:使用 | 分隔多個(gè)類型
- 字面量類型聯(lián)合:
type: 'success' | 'warning' | 'danger' = 'success'- 限定只能是特定可選值之一
- 類型聯(lián)合:
a: string | number = 100- 限定只能是可選類型之一
- 字面量類型聯(lián)合:
- 類型別名
type StringNumber = string | numbera: StringNumber = 'string'
- maybe類型
- 類型前加問號(hào)
a: ?number = undefined - 等同于
a: number | null | void
- 類型前加問號(hào)
- 字面量類型:
- Mixed與Any
- 可以接收任意類型
- Mixed:強(qiáng)類型
- 雖然可以接收任意類型,但是需要先明確變量是什么類型,才能進(jìn)行相應(yīng)的使用
- Any:弱類型
- 接收任意類型,并可以任意進(jìn)行使用
- 主要為了用來(lái)兼容未進(jìn)行強(qiáng)類型校驗(yàn)的老代碼
- 原始類型
-
運(yùn)行環(huán)境API
TypeScript
TypeScript是JavaScript的超集,在JavaScript基礎(chǔ)上擴(kuò)展了類型系統(tǒng)與ES6+新特性
-
優(yōu)點(diǎn):
- 類型系統(tǒng)使代碼可靠性更高,同時(shí)可以使用ES6+新特性
- 兼容性好,可以在任何使用JavaScript開發(fā)的環(huán)境使用TypeScript
- 生態(tài)健全、完善
- 漸進(jìn)式,可以只使用部分特性
-
缺點(diǎn):
- 增加了很多概念,例如:接口、枚舉、泛型
- 需要編寫大量類型聲明,對(duì)小型項(xiàng)目會(huì)增加開發(fā)成本
-
安裝
yarn add typescript --dev
-
執(zhí)行
-
yarn tsc typescript.ts- 編譯 typescript.ts 為 typescript.js 文件
- 進(jìn)行類型檢查
- 移除類型注解
- 轉(zhuǎn)換ES6+語(yǔ)法為ES3語(yǔ)法
-
-
配置文件
-
yarn tsc --init初始化創(chuàng)建配置文件 tsconfig.json - 配置項(xiàng)
- target
- 指定轉(zhuǎn)換為什么版本的ES標(biāo)準(zhǔn)代碼
- 不設(shè)置默認(rèn)es3,配置文件默認(rèn)es5,其他可選 es2015/es2016/es2017/...
- module
- 模塊化標(biāo)準(zhǔn)
- 默認(rèn)commonjs、其他可選 amd/umd/es2015/es2020/...
- sourceMap
- 源代碼映射,生成sourceMap,便于代碼調(diào)試
- outDir
- 指定編譯結(jié)果輸出目錄
- 可以配置dist
- lib
- 指定標(biāo)ts準(zhǔn)庫(kù)(ES對(duì)應(yīng)版本內(nèi)置對(duì)象的聲明文件),接收一個(gè)數(shù)組
- target
-
-
rootDir
+ 指定代碼根目錄
+ 可以配置src
+ strict
+ 開啟嚴(yán)格模式- 使用
yarn tsc直接運(yùn)行
- 使用
-
原始類型
- string
const a: string = 'hello'- 非嚴(yán)格模式可以是null或undefined
- number
const b: number = 123- 包含
NaNInfinity - 非嚴(yán)格模式可以是null或undefined
- boolean
const c: boolean = true- 非嚴(yán)格模式可以是null或undefined
- void
const d: void = undefined- 標(biāo)記函數(shù)返回類型
- 非嚴(yán)格模式可以是null
- null
const e: null = null
- undefined
const f: undefined = undefined
- symbol
const g: symbol = Symbol()- 需要配置target: es2015以上,或者配置lib引入es2015標(biāo)準(zhǔn)庫(kù)
- string
-
強(qiáng)制使用中文顯示錯(cuò)誤消息
yarn tsc --locale zh-CN- 修改VSCode setting中相關(guān)的配置
- 建議還是使用英文方式顯示,便于問題查詢定位
-
作用域問題
- 全局作用域下同名變量不能重復(fù)定義,可以放到函數(shù)作用域中,或者添加export {} 放到模塊作用域下
-
Object類型
-
const foo: object = {} // [] // function() {}可以接受數(shù)組、函數(shù)、對(duì)象 -
const obj: { name: string, value: number} = { name: 'hello', value: 123}- 強(qiáng)制對(duì)象類型的聲明,可以使用對(duì)象字面量
{}的方式,同時(shí)可以限制允許出現(xiàn)的屬性 - 使用接口定義更合適
- 強(qiáng)制對(duì)象類型的聲明,可以使用對(duì)象字面量
-
-
數(shù)組類型
const array: Array<number> = [1, 2, 3]const array: number[] = [1, 2, 3]
-
元組類型
- 元組是一種明確元素?cái)?shù)量和類型的特殊數(shù)組
const tuple: [number, string] = [123, '456']- 可以用來(lái)在一個(gè)函數(shù)中返回多個(gè)返回值
-
枚舉類型
-
enum關(guān)鍵字定義枚舉類型
enum Status { valid = 0, invalid } 枚舉值使用等號(hào)=賦值
如果不指定枚舉值,則默認(rèn)從0開始,依次遞增
如果指定枚舉值為數(shù)字,則默認(rèn)依次遞增
如果指定一個(gè)枚舉值為字符串,則需要指定
所有它之后的所有枚舉的初始的值-
枚舉類型會(huì)被編譯為雙向鍵值對(duì)對(duì)象,可以使用key獲得value,也可以使用value獲得key
var Status; (function (Status) { Status[Status["valid"] = 0] = "valid"; Status[Status["invalid"] = 1] = "invalid"; })(Status || (Status = {})); enum關(guān)鍵字前增加const時(shí)為常量枚舉,常量枚舉不可以使用枚舉值訪問枚舉的key
-
-
函數(shù)類型
-
函數(shù)聲明形式
function say (name: string, value: number, ...rest: number[]) : string { return `hello ${name}` } -
函數(shù)表達(dá)式形式
const said: (name: string, value: number, ...rest: number[]) => string = (name: string, value: number, ...rest: number[]): string => { return `hello ${name}` }函數(shù)表達(dá)式將函數(shù)賦值給一個(gè)變量,需要給變量一個(gè)函數(shù)類型,使用箭頭函數(shù)的形式
-
-
任意類型
- any類型
- 不會(huì)進(jìn)行類型檢查
- 用來(lái)兼容JS老代碼
- 存在類型安全問題
- any類型
-
隱式類型推斷
- 由typescript自行推斷變量的類型
- 建議給每個(gè)變量添加明確的類型
-
類型斷言
- 當(dāng)typescript無(wú)法明確推斷變量的類型時(shí),可以使用as關(guān)鍵字告訴typescript變量是什么類型
- 也可以使用
<number>尖括號(hào)<類型>的方式,但跟jsx混合使用的時(shí)候,會(huì)跟html標(biāo)簽混淆,建議使用as
-
接口
-
使用interface關(guān)鍵字定義接口,用來(lái)約束對(duì)象的結(jié)構(gòu)
interface Post { name: string value: number desc?: string readonly url: string } 屬性名后加問號(hào),表示可選屬性,可選屬性外的其他屬性必須存在
屬性名前加readonly關(guān)鍵字,表示只讀屬性,初始化后不可修改
不能包含接口定義外的其他屬性
-
-
類
面向?qū)ο缶幊讨械母拍?,用?lái)描述具體對(duì)象的抽象成員
ES6以前,使用構(gòu)造函數(shù)+原型的方式實(shí)現(xiàn)面向?qū)ο蟮念惻c繼承
ES6以后,提供了標(biāo)準(zhǔn)化的class來(lái)定義類
typescript增強(qiáng)了class的相關(guān)語(yǔ)法(訪問修飾符、抽象類等)
-
基本使用
class關(guān)鍵字定一個(gè)一個(gè)類
-
在類中聲明屬性,并初始化(定義時(shí)賦值,或在構(gòu)造函數(shù)constructor中初始化)
class Person { name: string age: number = 18 constructor(name: string, age: number) { this.name = name } }
-
訪問修飾符
控制類中屬性和方法的訪問級(jí)別
- public: 默認(rèn)
- private: 無(wú)法被類的實(shí)例訪問
- 如果constructor被private修飾,將不能使用new實(shí)例化
- protected: 無(wú)法被類的實(shí)例訪問,可以在子類中訪問
-
只讀屬性
- readonly關(guān)鍵字修飾類的屬性
- 只能在定義或者構(gòu)造函數(shù)中初始化,之后不能被修改
-
類與接口
同樣使用interface定義接口
在interface中定義類的方法,但不提供實(shí)現(xiàn)
-
class使用implements關(guān)鍵字實(shí)現(xiàn)一個(gè)或多個(gè)接口,必須包含接口中定義的方法的實(shí)現(xiàn)
interface Eat { eat(food: string): void } interface Run { run(speed: number): void } class Dog implements Eat, Run { eat(food: string) { console.log(food) } run(speed: number) { console.log(speed) } }
-
抽象類
-
使用abstract關(guān)鍵字定義抽象類
- 抽象類不能被new實(shí)例化,只能被繼承
-
使用abstract關(guān)鍵字定義抽象類的抽象方法
- 抽象方法不能具有實(shí)現(xiàn)
- 子類繼承后必須實(shí)現(xiàn)抽象方法
abstract class Animal { eat(food: string): void { console.log(food) } abstract run(speed: number): void } class Cat extends Animal { run(speed: number): void { } } const cat = new Cat() cat.eat('food')
-
-
泛型
函數(shù)定義后使用<T>定義泛型,參數(shù)的類型可以被指定為T
-
函數(shù)使用時(shí)在函數(shù)名后使用<類型>指明具體的類型,以此使函數(shù)在使用時(shí)可以傳入不同類型的參數(shù)
function hey<T>(value: T) { console.log(value) } hey<string>('123') hey<number>(123)
-
類型聲明
- declare關(guān)鍵字進(jìn)行類型聲明
- 使用第三方庫(kù)時(shí),如果沒有提供類型聲明文件,需要安裝相應(yīng)的類型聲明模塊
- 類型聲明模塊應(yīng)該是開發(fā)依賴
-