TypeScript筆記

安裝

npm i -D typescript

ts不能直接在瀏覽器環(huán)境執(zhí)行,需要先編譯成js文件。
文件編譯指令:
tsc [tsfile]
tsc [tsfile] -w 可以自動監(jiān)視改變并重新編譯

類型

number
string
boolean
字面量:聲明變量可能的值,不能是別的值或者超出字面量的范圍。let a: 10|11;a = 10;
any:任意值,可以被賦值不同類型的值。變量也可以賦值給其它類型的變量,不安全。
unknown:安全的any。可以是任何類型值。變量不允許直接被賦值給其它非unknown類型的變量。
void:空值null或者undefined。
never:不能是任何值。這種返回值一般用于系統(tǒng)報錯throw newError()
object:任意js對象。
array:數(shù)組。
tuple:固定長度數(shù)組。[1,2]聲明后就不能變長
enum:枚舉。enum{'a', 'b'}

變量聲明

let a: number;
a = 1;
let b: string = 'abc'

如果變量聲明同時直接賦值,則類型會默認對應(yīng)聲明,
let a = false
a = 123 // 提示錯誤

sum(a:number, b:number): number { // 聲明參數(shù)類型和函數(shù)返回值類型
return a + b
}
sum(1, '2') // 提示錯誤,但是編譯還是會過,可以通過配置讓編譯也不通過
sum(1, 2, 3) // 提示錯誤,參數(shù)個數(shù)不匹配

使用字面量聲明:類似于常量,聲明了一個或者多個后,后面的代碼賦值不能超出范圍。
let a: 'hello'; // a的值只能是'hello'不能聲明成別的
a = 'world' // 提示錯誤
let b: 'hello' | 'world'; // b的值只能是'hello'或者'world'

其他類型:
let a: any; // 不限制任何類型賦值
let b; // 如果聲明變量不指定類型也不直接賦值,則類型同any

開發(fā)中一般不允許使用any類型,因為any類型的變量可以賦值給任何類型變量,會出現(xiàn)嚴重的問題:
let a;
a = 10;
a = true;
let b: number;
b = a; // tsc編譯不報錯

如果真有這種業(yè)務(wù)場景,推薦使用unknown。unknown相當于是一種安全的any,也可以賦值任意類型,但是不能隨便賦值給其它類型的變量,直接復(fù)制會報錯,如果實現(xiàn)進行過類型檢查則可以賦值。
let a: unknown
a = 'hello'
let b: string
if (typeof a === 'string') { // 方式1
b = a
}
b = a as string // 方式2 使用斷言,斷言就是告訴編譯器,這個變量的類型一定為指定類型
b = <string>a // 方式3 另一種斷言

let a: object // js中一切皆對象,所以通常不會這樣使用,實際上開發(fā)者關(guān)注的應(yīng)該是對象的結(jié)構(gòu)(屬性方法什么的)
a = {}
a = function(){}
let b: {name: string, age?: number} // 這種使用方式比較推薦,使用b的時候必須設(shè)置name屬性,age可選
b = {name: 'sony'}
let b: {name: string, [propName: string]: any} // 這種方式也比較推薦,[propName: string]: any表示可以追加任意自定義屬性,propName是自定義的名字隨便寫,string表示屬性名類型為字符串
b = {name: 'sony', a: 12}

let a: Function // 聲明函數(shù),但是實際上沒人這么寫,沒什么意義,開發(fā)者關(guān)注的是函數(shù)的結(jié)構(gòu)(參數(shù)返回值什么的)
let a: (arg1: number, arg2: number) => number // 函數(shù)的聲明方式

let arr: Array<number> // 聲明一個數(shù)組,內(nèi)部元素類型為number
let arr: number[] // 作用和上面的等價

let arr: [number, number] // 聲明定長數(shù)組,賦值的時候必須一一對應(yīng),這種方式的優(yōu)勢在于性能比較好,分配固定的內(nèi)存空間就ok了

關(guān)于枚舉enum,它的使用意圖和“|”很類似,enum的優(yōu)勢在于兼顧了語義化和存儲空間。
例如聲明一個變量let a: '男'|'女',業(yè)務(wù)編碼使用的時候沒什么問題,但是數(shù)據(jù)庫或者數(shù)據(jù)傳遞的時候通常傾向于更小的空間占用,比如存0或者1這種值,enum就可以滿足這個需求。
開發(fā)中可以先定義一個enum類型的類,使用enum中的元素名就代表對應(yīng)的值(編譯器會默認賦值成0、1這種值)
enum Gender {
Male,
Female
}

let person: {name: string, gender: Gender}

person = {name: '張三', gender: Gender.Male} // 相當于gender: 0

另外,比較特殊的運算符“&”,聲明類型的時候表示同時滿足的意思:
let o: {name: string} & {age: number} // 表示變量o賦值的時候必須是一個對象并且同時有name和age屬性。

額外提一下ts中的“?”和“!”的用法:

  1. 作為運算符:“?”用在三目運算符中(例如a?b:c),“!”表示取反(例如!a)
  2. 參數(shù):“?”用在參數(shù)中表示可選項。例如function(a: string, b?: number)
  3. 成員變量:“?”表示可選項,“!”表示此項一定有值且不為null
  4. 安全鏈式調(diào)用:
    ?表示可能為null,如果為null就不往下執(zhí)行,場景:a.b?.c();
    !表示一定不為null,強制讓編譯器通過安全檢查,場景:a.b!.c();或者a.b!.c = xxx

面向?qū)ο?/strong>

ts的面向?qū)ο笫褂闷饋砼ces6基本一致:

// class聲明和使用
class Animal {
    static readonly type = '爬行動物' // 靜態(tài)屬性,readonly關(guān)鍵字表示只讀
    name = 'lucky' // 實例屬性

    // 構(gòu)造函數(shù)
    constructor(name: string = 'lucky') {
        this.name = name
    }

    // 實例方法,同樣,加了static就變成類靜態(tài)方法了
    eat() {
        console.log(this.name + ' is eating...')
    }

    static move() {
        console.log('animal can move')
    }
}
const cat = new Animal('happy')
console.log(cat, Animal.type) // {name: 'happy'} '爬行動物'
console.log('eat: ')
cat.eat()
console.log('move: ')
Animal.move()

class Dog extends Animal {
    eat() {
        console.log('dog: ' + this.name + ' is eating...')
    }
}
console.log(Dog.type)
const dog = new Dog()
console.log(dog, Dog.type)
dog.eat()

interface Human {
    name: string
    eat(): void
    speak(): void
}

class Soldier implements Human {
    name: string = '001'
    private _level: number
    constructor(name: string, level: number) {
        this.name = name
        this._level = level
    }

    get level(): number {
        return this._level
    }
    set level(value: number) {
        this._level = value
    }

    eat(): void {
        console.log(`soldier[level ${this.level}] ${this.name} is eating...`)
    }
    speak(): void {
        console.log(`soldier[level ${this.level}] ${this.name} is speaking...`)
    }
}

const orcSoldier = new Soldier('crom', 1)
orcSoldier.eat()
orcSoldier.speak()

// 泛型,生產(chǎn)中不允許使用any類型,如果確實有場景要應(yīng)對未知類型,或者類型是使用者自定義的,可以考慮使用泛型
function f<T, K>(t: T, k: K): T {
    console.log(`t: ${t}, k: ${k}`)
    return t
}
console.log(f(5, 3)) // 編譯器自動識別類型
console.log(f<string, number>('hello', 1)) // 手動指定類型,更加嚴謹,推薦方式

es6目前無法支持抽象類、接口、私有屬性修飾符private等面向?qū)ο蟮奶匦裕瑃s編譯器支持,但也只局限在檢查層面,比如對私有屬性賦值,雖然tsc檢查錯誤但是默認仍然可以正常編譯成js執(zhí)行,所以需要配置中"noEmitOnError": true 避免最終代碼出現(xiàn)邏輯漏洞。

編譯器配置

ts文件的需要先經(jīng)過編譯器執(zhí)行tsc指令編譯成js文件才能在瀏覽器環(huán)境執(zhí)行,開發(fā)過程中我們可以創(chuàng)建一個tconfig.json并根據(jù)需求配置參數(shù),編譯器會讀取配置文件并覆蓋默認配置。

ts配置文件跟普通json文件不太一樣,里面可以寫注釋。

{
  /* include:用于編譯指定目錄下的ts文件,**表示任意目錄,*表示所有文件 */
  "include": ["./src/**/*"],

  /* exclude:不編譯某些目錄下的文件 */

  /* extends:表示繼承某些配置文件,用于根據(jù)需要拆分組合配置 */

  /* files:直接編譯指定文件名,用于小微型的應(yīng)用開發(fā),不常用 */

  /* compailerOptions: 編譯配置項,可以定制編譯規(guī)則,可以讓代碼更嚴謹,減少程序出錯概率 */
  "compilerOptions": {
    // target表示編譯成什么樣的文件,具體指某個es版本,默認會編譯成es3,
    // 通常會編譯成es6(es2015)再配合webpack的babel-loader處理
    "target": "ES2015",
    // 指定模塊化規(guī)范
    "module": "ES2015",

    // 指定用到了哪些庫,方便ts編譯器識別,比如用了dom就可以在代碼中使用document否則會編譯報錯。
    // 這項通常不需要配置,默認配置已經(jīng)比較全。某些場景如nodejs環(huán)境或者用到一些默認不支持的lib會考慮配置
    // "lib": ["DOM"]

    // allowJS和checkJs一般成對使用,默認值是false,表示是否檢查和編譯js文件,
    // 有些情況下可能出現(xiàn)js文件模塊和ts文件模塊編譯后無法正常使用的問題,這時候會需要把js文件也編譯處理一遍
    "allowJs": true, 
    "checkJs": true,

    "removeComments": true, // 是否移除注釋,默認是false

    // "noEmit": false // 默認false,不生成編譯結(jié)果(target),不常用,某些情況下可能只是想使用編譯檢查功能的時候會設(shè)置這項

    // 默認false,只要編譯出錯就不生成target,
    // 在我們allowJs為true的時候,js文件即使檢查有錯誤,也會執(zhí)行編譯,這可能會出現(xiàn)錯誤隱患,
    // 如果要嚴格控制js文件和ts一視同仁,可以設(shè)置為true
    "noEmitOnError": true,

    // 嚴格模式的代碼在瀏覽器環(huán)境下執(zhí)行效率更好,
    // 通常模塊化引入的代碼默認都是嚴格模式,有些非模塊化代碼如果也需要嚴格模式(開頭加use strict),就需要配置此項
    "alwaysStrict": true,

    // 以下是一些常用代碼安全檢查規(guī)則

    // 默認false,如果配置了strict為true,則所有規(guī)則選項(包括下面的選項)都會被覆蓋為嚴格模式,如果想訂制,則不要配置此項
    // 開發(fā)中建議直接配置strict為true
    // "strict": true,

    // 不允許隱式any類型(不明確聲明類型),默認是false,any會導(dǎo)致編譯器不去判斷類型,造成代碼隱患 
    "noImplicitAny": true,

    // 不允許隱式this(不明確聲明this是什么類型),默認是false,原生js中this的指向非常靈活,跟動態(tài)調(diào)用環(huán)境有關(guān)系(執(zhí)行上下文),
    // 這也是bug隱患,如果是單純聲明一個function內(nèi)部想用this,可以考慮把“this”作為參數(shù)傳進來
    "noImplicitThis": true,

    // 是否嚴格檢查null值,默認false,有些操作如獲取dom,然后執(zhí)行dom.xxx()的時候,dom可能獲取失敗即是null,這樣執(zhí)行就會報錯,
    // 為了避免這個隱患,編譯器可以配置這個選項為true,代碼中可以用if判斷包裹,也可以使用ts語法dom?.xxx()
    "strictNullChecks": true

  }
}

ts-loader

開發(fā)中我們一般會使用webpack打包代碼,使用ts-loader編譯ts文件再通過babel-loader解決js的兼容性問題
ts-loader使用的時候建議先到官網(wǎng)上看下版本兼容相關(guān)信息,8.x和9.x分別對應(yīng)webpack4 和webpack5

npm i -D ts-loader typescript

  resolve: {
    // Add `.ts` and `.tsx` as a resolvable extension.
    extensions: [".ts", ".tsx", ".js"]
  },
  module: {
    rules: [
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      { 
        test: /\.tsx?$/,
        loader: "ts-loader",
        exclude: /node_modules/
      }
    ]
  }

然后別忘了把tconfig.json放到項目根目錄下

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內(nèi)容