TypeScript
一、JavaScript
1. 弱類型、動態語言的缺陷
-
程序中的異常在運行時才能發現
-
類型不明確函數功能會發生改變
-
對對象索引器的錯誤用法
2. 強類型的優勢
- 錯誤更早暴露
- 代碼更智能,編碼更準確
- 重構更牢靠
- 減少不必要的類型判斷
二、Flow
1. Flow是JavaScript類型檢查器
// : number 叫做類型註解
function sum (a: number, b: number) {
return a + b
}
console.log(sum(1, 2))
2. 如何安裝並使用flow
-
先執行
yarn init -y
-
執行
yarn add flow-bin
-
在代碼中第一行添加flow註釋:
// @flow
-
在函數中形參後面加上冒號和類型:
function sum (a: number, b: number)
-
執行
yarn flow init
創建.flowconfig -
執行
yarn flow
// @flow // : number 叫做類型註解 function sum (a: number, b: number) { return a + b } console.log(sum(1, 2)) console.log(sum('100', '100'))
3. 如何移除flow註解
flow官方提供的操作:
-
yarn add flow-remove-types --dev
-
yarn flow-remove-types src -d dist
使用babel配合flow轉換的插件:
-
yarn add @babel/core @babel/cli @babel/preset-flow --dev
-
.babelr
文件:{ "presets": ["@babel/preset-flow"] }
-
yarn babel src -d dist
4. 開發工具插件
VsCode中的插件:Flow Language Support
5. Flow支持的類型
/**
* 原始類型
* @flow
*/
const a: string = 'foo'
const b: number = Infinity // NaN // 100
const c: boolean = false // true
const d: null = null
const e: void = undefined
const f: symbol = Symbol()
const arr: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 元組
const foo: [string, number] = ['foo', 100]
const obj1: {foo: string, bar: number} = {foo: 'string', bar: 100}
// 問號表示可有可與的屬性
const obj2: {foo?: string, bar: number} = {bar: 100}
// 表示當前對象可以添加任意個數的鍵,不過鍵值的類型都必須是字符串
const obj3: {[string]: string} = {}
obj3.key1 = 'value1'
// obj3.key2 = 100
function fn (callback: (string, number) => void) {
callback('string', 100)
}
fn(function (str, n) {
})
const fo: 'foo' = 'foo'
// 聯合類型,變量的值只能是其中之一
const type: 'success' | 'warning' | 'danger' = 'success'
// 變量類型只能是其中的一種類型
const g: string | number = 100
type StringOrNumber = string | number
const h: StringOrNumber = 'stri' // 100
// maybe類型 加一個問號,變量除了可以接受number類型以外,還可以接受null或undefined
const gender: ?number = null
// 相當於
// const gender: number | null | void = undefined
// Mixed / Any mixed是強類型,any是弱類型,爲了兼容老代碼,是不安全的,儘量不用any
// string | number | boolean |...
function passMixed (value: mixed) {
}
passMixed('string')
passMixed(100)
function passAny (value: any) {
}
passAny('string')
passAny(100)
const element: HTMLElement | null = document.getElementById('root')
6. 運行環境API
三、TypeScript
TypeScript:JavaScript的超集/擴展集
1. 安裝並使用typescript模塊
-
yarn add typescript --dev
-
創建一個擴展名爲
ts
的文件,myTypeScript.ts
:// TypeScript 可以完全按照JavaScript 標準語法編碼 const hello = (name: string) => { console.log(`hello, ${name}`) } hello('TypeScript') // hello(111)
-
執行命令
yarn tsc myTypeScript.ts
, 會生成一個同名的js文件 -
查看
myTypeScript.js
文件:// TypeScript 可以完全按照JavaScript 標準語法編碼 var hello = function (name) { console.log("hello, " + name); }; hello('TypeScript'); // hello(111)
2. tsc命令的作用
tsc:(typescript compiler) 編譯ts文件: 執行命令yarn tsc myTypeScript.ts
- 檢查類型使用異常
- 移除註解之類的擴展語法
- 自動轉換ECMAScript的新特性
tsc編譯整個項目:
- 執行命令
yarn tsc --init
,生成tsconfig.json
文件 - 執行命令
yarn tsc
, 按照配置文件將src中的ts文件生成到了dist中的js文件,並且是採用ES2015語法
3. TS支持的原始類型
const a: string = 'foobar'
const b: number = 100 // NaN Infinity
const c: boolean = true // false
// const d: boolean = null // 嚴格模式下不支持賦值null
const e: void = undefined // 函數沒有返回值時的返回值類型
const f: null = null
const g: undefined = undefined
const h: symbol = Symbol()
4. TS標準庫聲明
標準庫就是內置對象所對應的聲明
在tsconfig.json中寫上:
"lib": ["ES2015", "DOM"],
5. 中文錯誤消息
yarn tsc --locale zh-CN
6. 作用域
每個文件都是全局作用域,所以在不同文件中定義同名變量會報錯,解決方案:
-
使用立即執行函數,產生作用域
(function () { const a = 123 } )()
-
使用export
const a = 11 export {} // 確保跟其他實例沒有成員衝突
7. Object類型
TypeScript中的Object類型泛指所有的的非原始類型。如對象、數組、函數.
object類型並不單指對象,而是指除了原始類型之外的其他類型.
對象的賦值必須與定義的屬性保持一致,不能多也不能少。更專業的寫法是用接口.
export {} // 確保跟其他實例沒有成員衝突
const foo: object = function () {} // [] // {}
const obj: {foo: number, bar: string} = {foo: 123, bar: 'string'}
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
function sum (...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3)
8. 元組類型
固定長度的數據。 例如Object.entries(obj)的返回值裏面的每一個元素都是一個元組
export {}
const tuple: [number, string] = [19, 'jal']
// 下標取值
// const age = tuple[0]
// const name = tuple[1]
// 數組解構
const [age, name] = tuple
9. 枚舉類型
// JS中沒有枚舉類型,則使用對象模擬枚舉類型
// const PostStatus = {
// Draft: 0,
// Uppublished: 1,
// Published: 2
// }
// 枚舉類型。使用時和對象屬性一樣
// 如果不指定值,則從0開始累加。如果制定了第一個成員的值,後面的成員則再第一個成員基礎上累加。值如果是字符串,就得指定具體的值
const enum PostStatus {
Draft = 0,
Uppublished = 1,
Published = 2
}
const post = {
title: 'Hello TypeScript',
content: 'Type...',
status: PostStatus.Draft
}
10. 函數類型
// 獲取不確定參數
// function func1 (a: number, b: number): string {
// function func1 (a: number, b?: number): string {
// function func1 (a: number, b: number = 10): string {
function func1 (a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func1(100, 200)
func1(100)
func1(100, 200, 300)
// 指定函數的形式
const func2: (a: number, b: number) => string = function (a: number, b: number ): string {
return 'f'
}
11. 任意類型
any類型是爲了兼容老的代碼,它還是動態類型,是不安全的,儘量少用
function stringify (value: any) {
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()
12. 隱式類型推斷
let age = 18 // ts推斷出類型是number
// age = 'str' // 會報錯 不能將類型“"str"”分配給類型“number”。
let foo // 此時無法推斷具體類型,foo則是動態類型,any類型
foo = 1 // 不會報錯
foo = 'string' // 不會報錯
13. 類型斷言
const nums = [110, 120, 119, 112]
const res = nums.find(i => i>0)
// const res: number | undefined
// const square = res * res
const num1 = res as number // 斷言 res 是number
const square = num1 * num1
const num2 = <number>res // 或者這種方式。JSX下不能使用
14. 接口
// 可以用分號分割,分號可以省略
interface Post {
title: String
content: String
}
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title: 'hello',
content: 'javascript'
})
可選屬性、只讀屬性
interface Post {
title: String
content: String
subtitle?: string // 可有可無的屬性。也就是說該屬性爲string或者undefined
readonly summary: string
}
const hello: Post = {
title: 'hello',
content: 'javascript',
summary: 'js'
}
//報錯: Cannot assign to 'summary' because it is a read-only property.
// hello.summary = '11'
動態屬性
interface Cache {
// 動態成員
[prop: string]: string
}
const cache: Cache = {}
cache.foo = 'ff'
15. 類
TypeScript增強了class的相關語法
-
類的基本使用
class Person { // ES2017定義的語法: name: string // = 'init name' age: number constructor(name: string, age: number) { this.name = name this.age = age } sayHi (msg: string): void { console.log(`I am ${this.name}`) } }
-
訪問修飾符:private public protected 。默認是public.
export {} class Person { // ES2017定義的語法: name: string // = 'init name' private age: number protected gender: boolean constructor(name: string, age: number) { this.name = name this.age = age this.gender = true } sayHi (msg: string): void { console.log(`I am ${this.name}`) } } const tom = new Person('tom', 18) console.log(tom.name) // console.log(tom.age) // 屬性“age”爲私有屬性,只能在類“Person”中訪問。 // console.log(tom.gender) // 屬性“gender”受保護,只能在類“Person”及其子類中訪問。 class Student extends Person { constructor(name: string, age: number) { super(name, age) // 父類的protected屬性子類可以訪問。 console.log(this.gender) } }
-
靜態屬性、構造器私有化後不能new
class Student extends Person { private constructor(name: string, age: number) { super(name, age) console.log(this.gender) } static create(name: string, age: number) { return new Student(name, age) } } const jack = Student.create('jack', 18)
-
只讀屬性,在屬性聲明前面加上readonly即可
protected readonly gender: boolean
16. 類與接口
// 儘可能讓接口簡單。一個接口只約束一個能力,一個類實現多個接口
interface Eat {
eat (foo: string): void
}
interface Run {
run (distance: number): void
}
class Person implements Eat, Run {
eat(food: string): void {
console.log(`優雅的進餐:${food}`)
}
run(distance: number): void {
console.log(`直立行走:${distance}`)
}
}
class Animal implements Eat, Run {
eat(food: string): void {
console.log(`呼嚕呼嚕的吃:${food}`)
}
run(distance: number): void {
console.log(`爬行:${distance}`)
}
}
17. 抽象類
被abstract修飾,不能被new,只能被繼承。繼承抽象類的子類,必須實現父類的抽象方法
abstract class Animal {
eat (food: string) : void {
console.log(`呼嚕呼嚕的吃:${food}`)
}
// 抽象方法不需要方法體,子類必須要實現抽象方法
abstract run(distance: number): void
}
// 非抽象類“Dog”不會實現繼承自“Animal”類的抽象成員“run”
class Dog extends Animal {
run(distance: number): void {
console.log(`四腳爬行:${distance}`)
}
}
const dog = new Dog()
dog.run(20)
dog.eat('fish')
18. 泛型
把類型作爲參數,放在尖括號中
function createNumberArray(length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
const res = createNumberArray(3, 100 ) // [100, 100, 100]
function createArray<T> (length: Number, value: T): T[] {
const arr = Array<T>(length).fill(value)
}
const arrRes = createArray<string>(3, 'foo') // ['foo', 'foo', 'foo']
19. 類型聲明
TypeScript中的擴展名爲d.ts
的文件就是類型聲明文件
import {camelCase} from 'lodash'
// 自己寫declare語句聲明類型
declare function camelCase (input: string): string
const res = camelCase('zjal')