TypeScript解決JavaScript類(lèi)型系統(tǒng)的問(wèn)題嗎,大大提高代碼的可靠程度
TypeScript是JavaScript的超集(擴(kuò)展JavaScript語(yǔ)法串远,提供更強(qiáng)大的類(lèi)型系統(tǒng)),會(huì)被編譯為JavaScript類(lèi)型
缺點(diǎn):
- 語(yǔ)言本身多了很多概念,增強(qiáng)學(xué)習(xí)成本(TypeScript屬于漸進(jìn)式)
- 項(xiàng)目初期,TypeScript會(huì)增加一些成本(長(zhǎng)久來(lái)說(shuō)很重要)
TypeScript安裝
- yarn init --yes初始化項(xiàng)目
- yarn add typeScript --dev 作為開(kāi)發(fā)依賴(lài)斯入,此時(shí)node_modules/.bin/tsc文件用于編譯typeScript
- yarn tsc xxx.ts 進(jìn)行編譯
- yarn tsc --init生成.tsconfig.json文件
- 按需修改配置文件(rootDir為ts文件目錄,outDir為輸出js文件目錄)
- 此時(shí)直接使用yarn tsc就可進(jìn)行指定目錄編譯
TypeScript使用指南
-
原始類(lèi)型
const a: string = 'foobar' const b: number = 100 // NaN Infinity const c: boolean = true // false // 在非嚴(yán)格模式(strictNullChecks)下蛀蜜, // string, number, boolean 都可以為空 // const d: string = null // const d: number = null // const d: boolean = null const e: void = undefined const f: null = null const g: undefined = undefined // Symbol 是 ES2015 標(biāo)準(zhǔn)中定義的成員刻两, // 使用它的前提是必須確保有對(duì)應(yīng)的 ES2015 標(biāo)準(zhǔn)庫(kù)引用 // 也就是 tsconfig.json 中的 lib 選項(xiàng)必須包含 ES2015 const h: symbol = Symbol() // Promise // const error: string = 100
-
作用域問(wèn)題
// a.js const a: string = 'a' // 默認(rèn)文件中的成員會(huì)作為全局成員 // b.js const a: number = 2 // 無(wú)法重新聲明塊范圍變量“a”。 // 解決 // 1.立即執(zhí)行函數(shù) (function() { const a: number = 2 })() // 2.使用export 把當(dāng)前文件變?yōu)槟K const a: number = 2 export {}
-
Object類(lèi)型
// 指所有非原始類(lèi)型 const foo: object = function() {} // 普通對(duì)象類(lèi)型實(shí)現(xiàn) 更專(zhuān)業(yè)的使用接口類(lèi)型實(shí)現(xiàn) const obj: { foo: number, bar: string } = { foo: 123, bar: 'a' }
-
數(shù)組類(lèi)型
// 兩種定義方式 const arr: number[] = [1,2,3] const arr: Array<number> = [1,2,3] function sum(...args: number[]) { // 如果是 JS滴某,需要判斷是不是每個(gè)成員都是數(shù)字 return args.reduce((prev, current) => prev + current) } sum(1,2,3)
-
元組類(lèi)型
// 明確元素?cái)?shù)量以及每個(gè)元素類(lèi)型的數(shù)組 const tuple: [number, string] = [12, 'wang'] const [age, name] = tuple // 編譯為js后實(shí)際相當(dāng)于以下代碼 // const age = tuple[0] // const name = tuple[1] // Object.entries獲取到每個(gè)鍵值對(duì)就是元組 固定長(zhǎng)度 固定類(lèi)型 const entries: [string, number][] = Object.entries({ foo: 123, bar: 456 }) const [key, value] = entries[0]
-
枚舉類(lèi)型
// 對(duì)象模擬實(shí)現(xiàn)枚舉 const PostStatus = { Draft: 0, Unpublished: 1, Published: 2 } enum PostStatus { Draft, // 不設(shè)置值時(shí)默認(rèn)從0開(kāi)始遞增 相當(dāng)于Draft = 0,Unpublished = 1,Published = 2 Unpublished, Published } enum PostStatus { Draft = 6, // 相當(dāng)于Draft = 6,Unpublished = 7,Published = 8 Unpublished, Published } // 常量枚舉磅摹,不會(huì)侵入編譯結(jié)果 const enum PostStatus { Draft, Unpublished, Published }
-
函數(shù)類(lèi)型
// 函數(shù)聲明 // 輸入輸出類(lèi)型限制 function fun1(a: number, b: number): string { return 'fun1' } fun1(1, 2) // 如果一個(gè)參數(shù)可有可無(wú) function fun1(a: number, b?: number): string { return 'fun1' } function fun1(a: number, b: number = 2): string { return 'fun1' } // 如果需要傳入多個(gè)參數(shù) function fun1(a: number, b: number = 2, ...rest: number[]): string { return 'fun1' } // 函數(shù)表達(dá)式 const fun2: (a: number, b: number) => string = function (a: number,b: number): string { return 'fun2' }
-
任意類(lèi)型
function stringify(value: any) { return JSON.stringify(value) } stringify('string') stringify(100) stringify(true) let foo: any = 'string' foo = 100 foo.bar() // any時(shí)類(lèi)型不安全的
-
聯(lián)合類(lèi)型
// 聯(lián)合類(lèi)型 通過(guò)|將變量設(shè)置為多種值 let strOrNum: string | number = 2 strOrNum = 'sdf' let arr: string[] | number[] arr = [1, 2, 3] arr = ['foo', 'bar', 'baz'] // 函數(shù)參數(shù) function add(name: string | string[]): void { }
-
隱式類(lèi)型推斷
let age = 12 // typeScript推斷此類(lèi)型為number age = 'string' // 不能將類(lèi)型“string”分配給類(lèi)型“number” // 盡可能給每個(gè)變量添加類(lèi)型
-
類(lèi)型斷言
const nums = [12, 13, 14] const res = nums.find(i => i > 0) // 類(lèi)型斷言 const num1 = res as number // const num1 = <number>res // JSX下不能使用 const square = res * res
-
接口
// 規(guī)范或契約 約定一個(gè)對(duì)象的結(jié)構(gòu) interface Post { title: string content: string subtitle?: string // 可選成員 readonly summary: string // 只讀成員 } function printPost(post: Post) { console.log(post.title) console.log(post.content) } printPost({ title: 'hello', content: 'China' }) // 動(dòng)態(tài)對(duì)象 定義時(shí)無(wú)法知道有哪些具體成員 interface Cache { [prop: string]: string } const cache: Cache = {} cache.foo = 'value1' cache.bar = 'value2'
-
類(lèi)的基本使用
// 描述一類(lèi)具體事物的抽象特征 // ES6之前,通過(guò)函數(shù) + 原型模擬實(shí)現(xiàn)類(lèi) // TypeScript增強(qiáng)了class的相關(guān)語(yǔ)法 // 訪(fǎng)問(wèn)修飾符 private私有屬性 只能在當(dāng)前訪(fǎng)問(wèn) public共有屬性 protected只能在繼承的子類(lèi)中訪(fǎng)問(wèn) 相比于private允許繼承 // readonly 只讀屬性 不能被修改 class Person { public name:string private age: number protected readonly gender: boolean constructor (name: string, age: numberr) { this.name = name this.age = age } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) } }
-
TypeScript類(lèi)與接口
// 使用接口明確強(qiáng)制一個(gè)類(lèi)去符合某種契約 // 接口描述類(lèi)的公共部分 // 一個(gè)接口盡量只定義一個(gè)方法 interface Eat { eat(food: string):void } interface Run { run(distance: number): void } class Animal implements Eat, Run { eat(food: string): void { console.log(`大口吃:${food}`) } run(distance: number): void { console.log(`爬行:${distance}`) } } class Person implements Eat, Run { eat(food: string): void { console.log(`細(xì)嚼慢咽的吃:${food}`) } run(distance: number): void { console.log(`行走:${distance}`) } }
-
抽象類(lèi)
// abstract修飾 只能被繼承 不能使用new創(chuàng)建實(shí)例 // 有抽象方法的類(lèi)必須被聲明為抽象類(lèi) // 和接口相似 抽象方法也是定義但不實(shí)現(xiàn) 相比接口 抽象類(lèi)可以包含成員的實(shí)現(xiàn)細(xì)節(jié) abstract class Animal { eat(food: string): void { console.log(`大口吃:${food}`) } abstract run(distance: number): void // 抽象方法 不包含具體實(shí)現(xiàn) 須在派生類(lèi)中實(shí)現(xiàn) } class Dog extends Animal { run(distance: number): void { console.log('四腳爬行', distance) } } const d = new Dog() d.eat('嗯西馬') d.run(100)
-
泛型
// 聲明時(shí)不指定類(lèi)型 調(diào)用時(shí)在指定類(lèi)型 // 使用泛型創(chuàng)建可重用的組件 function createStringArray (length: number, value: string): string[] { return Array<string>(length).fill(value) } function createNumberArray(length: number, value: number): number[] { return Array<number>(length).fill(value) } const res = createStringArray(4, 'ff') console.log(res); const res1 = createNumberArray(4, 100) console.log(res1); // 使用泛型的方式 function createArray<T>(length: number, value: T): T[] { return Array<T>(length).fill(value) } const res2 = createArray<string>(3, 'foo') const res3 = createArray<number>(3, 45) console.log(res2); console.log(res3);
-
類(lèi)型聲明
? 第三方npm模塊 這些npm模塊不一定通過(guò)typeScript編寫(xiě) 無(wú)法使用TypeScript類(lèi)型檢查等功能霎奢;需將庫(kù)里的函數(shù)和方法體去掉只保留導(dǎo)出類(lèi)型聲明户誓,產(chǎn)出一個(gè)描述JavaScript庫(kù)和模塊信息的聲明文件,引入此聲明文件 就可以借用TypeScript的各種特性來(lái)使用庫(kù)文件
-
引入模塊對(duì)應(yīng)的類(lèi)型聲明模塊@types/xx
// 安裝lodash的類(lèi)型聲明模塊就可正常使用 yarn add @types/lodash --dev import { camelCase } from 'lodash' const res = camelCase('hello typed')
-
image-20210112145412070.png
-
內(nèi)部已集成類(lèi)型聲明文件
// 內(nèi)部已經(jīng)繼承了類(lèi)型聲明文件 所以不用在聲明 import qs from 'query-string' qs.parse('?key=value&key2=value2')
-
如果沒(méi)有類(lèi)型聲明模塊時(shí)幕侠,自定義declare 關(guān)鍵字來(lái)定義類(lèi)型
// 以$符號(hào)為例 // 需要使用declare關(guān)鍵字來(lái)定義它的類(lèi)型 幫助TypeScript判斷我們傳入的參數(shù)類(lèi)型 declare const $: (selector: string) => any $('#foo')