TypeScript 學習筆記
TypeScript
- JS 自有型別系統的問題
- 1. 語言型別的分類
- 強型別與弱型別
- 靜態型別與動態型別
- 2. JS自有型別系統的問題
- JavaScript 型別系統問題解決方案
- TypeScript
- TypeScript的認識
- 快速上手
- TypeScript 的語法
- 1. TS 六種原始型別
- 2. 讓TS以中文提示錯誤訊息
- 3. TS 作用域問題
- 4. TS中的Object 型別(除了原始型別以外的其他型別)
- 5. TS 中定義任意型別
- 6. TS 的隱式型別推斷機制
- 7. TS 型別斷言
- 8. TS 介面
- 9. TS 中的 類
- 10. 類中的介面
- 11. 抽象類
- 12. 泛型
- 13. TS 型別宣告
JS 自有型別系統的問題
1. 語言型別的分類
強型別與弱型別
編程語言的劃分從安全的維度劃分
強型別:變數型別定義之后不會任意進行隱式型別轉換 (JAVA)
弱型別:會進行隱式轉換 (JS)
強型別優勢
- 錯誤更早暴露,如:編譯時就知道代碼的錯誤了
- 代碼更智能,編碼更準確,如:編輯器知道變數型別,會實時進行提示
- 減少不必要的型別判斷,
靜態型別與動態型別
編程語言從型別檢查的維度劃分
靜態型別:變數在宣告的時候其型別就是明確的,宣告過后他的型別是不允許進行隨意的修改的
動態型別:變數是沒有型別的,變數的型別取決于代碼運行時值的型別
2. JS自有型別系統的問題
JAVASCRIPT 屬于弱型別&動態型別語言
弱型別&動態型別語言的缺點
- “任意”
- “不靠譜”
- 由于JS是屬于腳本語言,不需要進行編譯,其執行依賴運行環境,代碼錯誤往往都是運行時才能夠發現錯誤,而不能夠在編譯的時候就知道錯誤的所在,
// 弱型別的問題
// 進行隱式轉換,使函式功能發生改變了
// 這樣的結果不是我們期待的結果,我們期待的時求兩個數的和
function add(num1, num2) {
return num1 + num2
}
add(100, '200') // 100200
JS 為什么會設計成弱型別&靜態型別語言哪?
這是歷史遺留問題,早期的web應用都是非常簡單的應用,不需要太多代碼就可以實作一個應用,如果在有型別檢查會顯得復雜且多余,但現在隨著web應用越來越復雜龐大,之前的語言設計就顯得力不從心,
JavaScript 型別系統問題解決方案
- Flow FACEBOOK團隊推出的JS型別檢查器來進行型別檢查 Flow的文章
- 使用 TypeScript
TypeScript
TypeScript的認識
- 根據前面的點我們知道JavaScript語言設計的不足在于其是弱型別&動態型別的語言,不會進行型別檢查.不適合于開發大型應用.
- TypeScript是為了解決JavaScript自有型別系統的問題而誕生的,TypeScript是JavaScript的超集.
- TypeScript中也可以寫ES6+的語法,在編譯的時候會轉換為目標,相當于會有個babel的功能
快速上手
快速上手查看官方檔案
TypeScript中文官方手冊
當運行 tsc 對ts代碼進行編譯的時候

TypeScript 的語法
1. TS 六種原始型別
// TypeScript 原始資料型別
// Number
const num: number = 1234
const str: string = '1234'
const _undefined: void = undefined
const _boolean: boolean = true
const _null: null = null
const _symbol: symbol = Symbol()
// 需要注意的點是:
// 1. 非嚴格模式下 變數可以為null || undefined || 所定義的型別
// 嚴格模式下 定義的變數只能夠是所定義的型別
// 2. tsconfig組態檔默認編譯代碼是ES5,所使用的標準庫也是ES5的,ES5的ts標準庫沒有對ES6內置物件進行定義,所以使用定義symbol型別會出現錯誤
// 解決辦法修改tsconfig中lib配置為['ES2015', 'DOM'],
// DOM標準庫包含BOM DOM
// 所謂的標準庫就是TS對JS內置物件,api的定義,可以理解為代碼檢查規則組態檔,

2. 讓TS以中文提示錯誤訊息
- 運行npx tsc --locale zh-CN
- vs code 中 修改設定里面找到 typescript locale配置
3. TS 作用域問題
如下圖描述
test.ts中定義了a變數

test1.ts中同樣定義a變數

解決辦法就是讓每一個檔案形成自己的作用域.

4. TS中的Object 型別(除了原始型別以外的其他型別)
export { }
// object型別指原始型別一外的其他型別
const a: object = function () { }
const b: object = / /
// 1. object 物件型別的限制可以使用 字面量的形式進行限制
const obj: { name: string, age: number } = { name: 'reborn', age: 18 }
// 2. 陣列型別
// 表示定義的陣列必須都是數字型別
const arr: number[] = [1, 2, 3]
// 泛型定義陣列, 這個與上面是相同的意思
const arr1: Array<number> = [1, 2, 3]
// 3. 元組型別的定義
// 元組含義是明確元素數量以及明確元素型別的陣列
// 如下:定義個三個元素,第一個為number型別,第二個為string型別,第三個為boolean型別
const tuple: [number, string, boolean] = [1, '1', false,]
// 4. 列舉型別
// 1. 通過enum關鍵字可以定義列舉資料結構,列舉資料結構一般都是定義一些常量的,如下面定義文章的狀態型別,
const enum postStatus {
draft = 0,
unpublished = 1,
published = 2
}
console.log(postStatus['draft'])
// 上面代碼會被編譯成如下代碼,定義了一組以物件值作為鍵的資料,一組以物件鍵作為鍵
// postStatus {draft: 0, 0: draft, unpublished: 1, 1: unpublished, published: 2, 2: published}
// (function (postStatus) {
// postStatus[postStatus["draft"] = 0] = "draft";
// postStatus[postStatus["unpublished"] = 1] = "unpublished";
// postStatus[postStatus["published"] = 2] = "published";
// })(postStatus || (postStatus = {}));
// 2. 另外一點可以直接定義常量列舉,只需要在 enum關鍵字前面加上 const,這樣編譯出來的代碼直接是列舉值了,
// console.log(0 /* 'draft' */);
// 注意的點:
// 列舉資料可以分為 字串列舉與 數字列舉
// 數字列舉可以不用定義值,默認會從 0 開始,如上面postStatus {draft,unpublished,published}, 會得到 {draft = 0 ,,,}
// 數字列舉定義第一個值,后面的值會默認補全,如上面postStatus {draft = 8,unpublished,published}, 會得到 {draft = 8 , unpublished = 9,published = 10 }
// 字串列舉必須要定義相應的值
// 5. 函式型別
// 1) 函式字面量宣告
// fn1 函式的形參必須是兩個number 型別,該函式的回傳值必須是number型別
function fn1(num1: number, num2: number): number {
return num1 + num2
}
// 2) 函式運算式宣告
// 函式運算式會有一個變數fn2接受一個函式,當前變數也可以進行型別定義,表面接受什么樣的函式
// 如fn2表示,它只能夠接受一個為字串的引數,且沒有回傳值的函式
const fn2:(greeting: string) => void = (greeting: string): void => {
console.log(`${greeting} Reborn~`)
// 6. Date型別
const date: Date = new Date()
}
// 7. RegExp
const reg: RegExp = /^/
5. TS 中定義任意型別
// Any型別
// 表示,hello函式可以接受任意型別引數,
// any 型別不會有TS型別檢查,一般是用于兼容老的代碼,
function hello(greeting: any): void {}
6. TS 的隱式型別推斷機制
TS 具有隱式型別推斷機制.下圖我們并沒有給變數 a 添加上型別注解, 但給 a 變數賦值了number型別的2,此時 TS 就會推斷改資料型別為number型別,當我們再次給a賦值字串’3423’的時候,VsCode就會有報錯提示.
雖然說隱式型別推斷機制能夠讓我們不用去寫型別注解為我們開發提供方便,但是不建議采用次機制.

7. TS 型別斷言
// TS 的型別斷言
// TS 型別斷言的應用場景
// 1. 假設arr是來自 后臺介面 回傳的資料
const arr = [1,2,3,4]
// 2. 我們需要查找 為 2 的資料
const target = arr.find( item => item === 2)
// 4. 這時候可以采用型別斷言,告訴 TS 我們確認改型別為 number
// - 采用 as 關鍵字
const result = target as number
// - 采用泛型也可以進行型別斷言 , 不過再寫 jsx 的時候泛型的尖括號會與html標簽進行沖突
// const result = <number> target
// 3. 此時就不能夠進行 * 運算,因為target 型別有可能為 number 有可能為 undefined
const res = result * result
8. TS 介面
一句話用來約束物件的結構(成員的型別, 成員個數),在實際的編譯時并不會編譯為JS代碼.
// TS 介面
// 用來約束物件成員
// 1. 通過interface關鍵字約定介面
interface Post {
title: string
content: string
subTitle?: string
// 2. 可選成員, 只讀成員, 動態成員
// - 通過 ? 定義 可選成員
// - 通過 readonly 關鍵字定義只讀成員
// - 通過 物件的 key 的計算屬性定義 動態成員
readonly summary: string
}
function printPost(post: Post): void {
console.log(post.title)
console.log(post.content)
console.log(post.summary)
}
printPost({title: 'reborn', content: 'vergood', summary: '哈哈哈哈'})
// - 通過 物件的 key 的計算屬性定義 動態成員
// 設定動態成員,就可以為物件添加任意成員,
// 下面介面表示可以為物件添加任意成員, 型別約束為了 key 為str, value str
interface dongtai {
[dd: string]: string
}
const ojb: dongtai = {
hello : 'hello',
age: '18'
}
TS 中定義的介面不會進行編譯成JS

9. TS 中的 類
const { log } = console
// TS 中類的使用
// 1. 為實體添加屬性的時候,需要先對屬性進行宣告
// 3. 可以給類的成員定義訪問修飾符如 private 定制私有屬性,public定義 公有屬性(默認) protected 受保護的(只允許在子類訪問該成員)
class Person {
// 2. ES2016 可以直接在物件中通過 變數名= 值 的形式為 實體賦值屬性
public name: string
// name?:string = undefined
// 6. private 關鍵字定義的變數僅適用于當前 類的內部使用
private age: number
protected gender: boolean
// 7. 通過添加 readonly 關鍵字 標注物件是只讀屬性
public readonly weight:number = 180
// 4. 給建構式定義為公有型別,可以在外部通過new 關鍵字創建實體,如果為 private 只能夠在建構式內部創建實體
public constructor(name: string, age: number, gender: boolean) {
this.name = name
this.age = age
this.gender = gender
}
public sayHi():void {
log(this.age)
}
}
class Student extends Person {
public constructor(name: string, age: number) {
super(name, age, false)
// 5. protected 關鍵字定義的屬性僅適用于子類繼承訪問
log(this.gender, 'protected')
}
}
10. 類中的介面
const { log } = console
// 實作類的結構
// 需求:
// 現在需要定義兩個類 Person Animal 類, 都有相同行為 吃 與 行走等行為,此時我們可以通過介面進行抽象公共方法
// 定義類的介面
// 表示該資料型別要有 eatFood 和 walk 的行為(方法)
interface EatAndWalk {
eatFood(food: string): void
walk(where: string): void
}
class Person implements EatAndWalk {
public eatFood(food: string): void {
log(`eat ${food}`)
}
public walk(where: string): void {
log(`${where} on street `)
}
}
class Animal implements EatAndWalk {
public eatFood(food: string): void {
log(`eat ${food}`)
}
public walk(where: string): void {
log(`${where} on street `)
}
}
11. 抽象類
// 抽象類
// 我所理解的抽象類更像是某一類事物的源頭(祖先類),如 動物類是 就是抽象類,小貓就是他的子類,
// 抽象類僅適用于繼承不能夠通過 new 關鍵字去創建實體, 僅用于子類的繼承
// 通過 abstract 定義
abstract class Animal {
eat(food: string): void {
console.log(`eat ${food}`)
}
// 也可以定義抽象方法,當父類有抽象方法的時候,其子類也必須要有所定義的方法,
abstract run(distance: number): void
}
class Cat extends Animal {
constructor(food: string) {
super()
this.eat(food)
}
run(distance: number): void {
}
}
// let animal = new Animal() // TS會報錯
12. 泛型
// 泛型
// 在宣告的時候不去指定具體資料型別,在呼叫的指定資料的型別
// 請看下面的例子
// 給createArra 宣告了一個泛型型別T, 并將所有不明確的型別都定義成T,在函式呼叫的時候指定該型別是什么型別的,
function createArra<T>(length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const resNumberArr = createArra<number>(3, 100)
console.log(resNumberArr)
const resStringArr = createArra<string>(3, '333')
console.log(resStringArr)
13. TS 型別宣告
import { upperCase } from 'lodash'
// TS 型別宣告
// 如果引入的第三方模塊不是 ts模塊的的話,型別系統會失效,必須要自己手動宣告方法型別
// 1. 宣告 upperCase方法
declare function upperCase(str: string):string
// 2. 此時呼叫upperCase就會進行型別檢查
const res = upperCase('hello')

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/271245.html
標籤:其他
上一篇:演算法面試記錄-某集團公司
