📢 大家好,我是小丞同學,一名大二的前端愛好者
📢 這篇文章是學習 TypeScript 的學習筆記
📢 非常感謝你的閱讀,不對的地方歡迎指正 🙏
📢 愿你忠于自己,熱愛生活
1. 搭建環境
全域安裝 typesctipt
npm i -g typescript
創建一個 TS 檔案
console.log('Hello Ts');
通過命令轉化 TS
tsc '檔案名'
2. 基本型別
js 是動態型別語言,所以有很多時候都不會報錯,但是會存在很多的問題
1. number
定義一個 number 型別的值
let a: number
a = 10
a = 'hello' //這一行代碼會報錯,因為 a 的變數型別是 number ,不能賦值字串
但是編譯還是會成功的
2. string
定義一個 string 型別的值
let b: string
b = 'hello'
b = 10 // b
3. boolean
宣告完直接賦值
let c: boolean = true
如果變數的宣告和賦值是同時進行的,TS 可以自動對變數進行型別檢測
let c = false
c = 123 // 報錯
4. 字面量
限定取值范圍為男和女
let d: '男' | "女"
d = '男'
5. any
任意型別,相當于對改變數關閉了型別檢測,顯示 any
使用 TS ,不建議使用 any
let e: any
e = 1
e = 'hello'
宣告變數不指定型別,就會被設定為 any,隱式 any
6. unknown
unknown 表示未知型別,是一個型別安全的 any
unknown 型別的變數,不能直接賦值給其他變數
let f: unknown
f = 'hello'
f = 1
f = true
型別斷言
當我們需要將 unknown 型別的變數賦值給其他型別的變數的時候,我們可以給他指定型別
c = f as boolean
// 第二種寫法
c = <boolean>f
7. 函式回傳型別
在括號后面跟上一個指定的型別
function sum(a: number, b: number): number {
return a + b
}
void 表示空,表示沒有回傳值
never 表示永遠不會回傳值
8. object
// 指定物件包含的屬性
let b: { name: string }
b = { name: '小丞' }
必須物件成員完全一致,如果物件中有可選屬性,我們可以采用 ? 來處理
let b: { name: string, age?: string }
b = { name: '小丞' }
這樣有沒有 age 都可以
如果需要設定任意都可以,可以采用下面的方式
let b: { name: string, [propName: string]: any }
但是一定要有 name 成員
9. array
宣告指定型別的陣列
let e: string[]
e = ['a', 'b']
也可以用這種方法
let f: Array<number>
10. 元組
固定長度的陣列
let h: [string, string]
h = ['hello', 'asd']
h = [123, 'saf'] // 錯誤
11. enum
enum Gender {
Male,
Female
}
// 指定列舉型別
let i: { sex: Gender }
// 設定值
i = {
sex: Gender.Male
}
12. & 使用
這里表示且 的意思,也可以用 |表示或噢
let j: { name: string } & { age: number }
j = { name: 'nan', age: 20 }
13. 型別的別名
type myType = 1 | 2 | 3 | 4 | 5
用來簡化型別的書寫
3. 編譯選項
tsconfig.json 是 ts 的組態檔,可以根據這個資訊來進行代碼編譯
include 表示需要編譯的檔案,** 表示任意檔案夾,* 表示任意檔案
"include": [
"./src/**/*"
]
指定 src 下任意目錄的任意檔案
exclude 表示排除的檔案,不需要編譯的檔案,一般不用,和 include 的用法一樣
重頭戲 compilerOptions
它是一個物件,里面有很多的配置
1. target
target 用來配置編譯后的 js 版本
"compilerOptions": {
"target": "ES3"
}
例如這里,我們指定編譯版本為 ES3

ES6 語法就會降級為 ES3
2. module
需要使用的模塊化方案
"module": "ES2015"
有以下可選值
'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'.
3. lib
用來指定專案使用到的庫
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"]
}
4. outDir
指定編譯后檔案所在的目錄
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"],
"outDir": "./dist"
}
5. outFile
把代碼合并成一個檔案
設定outFile 后,把所有全域作用域中的代碼合并到一個檔案
只有模塊化規范為 amd 和 system 時可以合并
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"],
"outDir": "./dist",
// "outFile": "./dist/app.js"
}
6. allowJS
是否對 JS 檔案進行編譯,默認是 false
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"],
"outDir": "./dist",
// "outFile": "./dist/app.js"
"allowJs": false
}
7. checkJS
是否檢查 JS 代碼是否符合語法規范,默認 false
"checkJs": false
8. removeComments
是否移除注釋,默認是 false
"removeComments": true
9. noEmit
不生成編譯后的檔案,默認是 false
只想用來檢查語法的時候可以用
"noEmit": true
10. noEmitOnError
決定編譯報錯的時候是否編譯,默認是 false
"noEmitOnError": true
11. alwaysStrict
用來設定編譯后的檔案是否使用嚴格模式,默認為false
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"],
"outDir": "./dist",
// "outFile": "./dist/app.js"
"allowJs": false,
"checkJs": false,
"removeComments": true,
"noEmit": true,
"noEmitOnError": true,
"alwaysStrict": true
}
12. noImplicitAny
是否允許隱式的 any 型別
"noImplicitAny": true
13. noImplicitThis
是否允許隱式的 this
"noImplicitThis": true
14. strictNullChecks
檢查是否存在空值
"strictNullChecks": true
可以用
a?.b
來改正
15. strict
開啟所有的嚴格檢查
"strict": true
全部配置
{
"include": ["./src/**/*"],
// "exclude": [],
"compilerOptions": {
"target": "ES3",
"module": "ES6",
"lib": ["DOM", "ES6"],
"outDir": "./dist",
// "outFile": "./dist/app.js"
"allowJs": false,
"checkJs": false,
"removeComments": true,
"noEmit": true,
"noEmitOnError": true,
"alwaysStrict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strict": true
}
}
4. webpack 打包 TS
1. 安裝依賴包
安裝一些依賴包,webpack 兩個包推薦全域安裝
yarn add webpack webpack-cli typescript ts-loader
2. webpack 組態檔
創建一個 webpack.config.js 檔案
const path = require("path");
// 所有配置資訊都寫在這里
module.exports = {
// 指定入口檔案
entry: "./index.ts",
output: {
// 指定打包檔案目錄
path: path.resolve(__dirname, "dist"),
// 打包后檔案的名字
filename: "bundle.js",
},
// 指定使用的模塊
module: {
rules: [
{
// test 指定的是規則生效的檔案
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
};
3. 修改組態檔
在 package.json 的組態檔中,添加 build 命令,啟動 webpack 打包
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
4. 引入 html 插件
安裝 html-webpack-plugin 包
yarn add html-webpack-plugin
引入插件
const HTMLWebpackPlugin = require("html-webpack-plugin")
配置插件
plugins:[
new HTMLWebpackPlugin()
]
后面的 webpack 沒什么價值,之前學過了,在這里學浪費時間,建議學第 1 節就好了
面向物件建議直接跳到抽象類,浪費時間
5. 抽象類
當我們不需要這個類來創建物件的時候,我們就可以使用物件類
例如,我們在創建 Dog 類的時候,需要繼承 Animal 類,但是我們并不需要 animal 類來創建東西,為了避免它被用來創建物件,因此我們可以使用抽象類 abstarct
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
console.log('動物在叫');
}
}
這樣我們就把 Animal 物件創建為了抽象類,那我們就不能使用它來創建物件了
const aaa = new Animal('sss') // 報錯
我們可以在抽象類中添加抽象方法,沒有方法體
// 定義抽象方法
abstract sayHello():void
只能定義在抽象類中,子類必須對抽象方法進行重寫
6. 介面
介面時用來定義一個類結構,用來定義一個類中應該包含哪些屬性和方法的
它和 type 有一點相似互通之處
我們可以采用 type 來描述一個物件型別
type myType = {
name: string,
age: number
}
我們也可以用介面來宣告一個型別
interface myInterface {
name: string,
age: number
}
我們可以正常的呼叫它
const obj: myInterface = {
name: 'sss',
age: 111
}
在這一點上,interface 和 type 的區別在于,type 只能宣告一個,而 interface 可以宣告多次,例如
interface myInterface {
name: string,
age: number
}
interface myInterface {
sex: string
}
這樣就以 2 個介面合并起來為準
介面可以用來在定義類的時候用來限制類的結構
介面中的所有屬性都不能有實際的值,介面只定義物件的結構,而不考慮實際值,在介面中所有的方法都是抽象方法
例如這里,我們限制了一個類,有 name還有一個 sayHello 的函式
interface myInterface {
name: string,
sayHello(): void
}
我們寫一個類來實作這個介面
我們需要采用 implements 指定我們要實作的介面是哪一個
class Myclass implements myInterface {
name: string
constructor(name: string) {
this.name = name
}
sayHello() {
console.log('好~ ');
}
}`
在介面中定義一個標準,指定我們需要去實作一個類 ,在我們創建類的時候需要指定它需要實作的介面,使用
implements
7. 屬性的封裝
現在屬性是在物件中設定的,屬性可以任意的被修改,這樣會
導致物件中的資料變得非常不安全
我們可以在屬性前添加屬性的修飾符
public修飾的屬性可以在任意位置訪問private定義為私有屬性,私有屬性只能在類內部訪問- 通過類中添加方法使得私有屬性可以被外部訪問
protected受包含的屬性,只能在當前類和當前類的子類中訪問
// 定義私有變數
private name: String
// 定義操作的方法
setName(value: string) {
this.name = value
}
// 修改 name 的值
per.setName('豬豬')
這樣我們如果不需要修改時,我們可以把修改 name 的方法隱藏起來,如果需要限制修改的值,我們可以添加 if 判斷
我們也可以采用 getter 和 setter 來設定存取器
get name() {
return this._name
}
這樣我們就可以直接使用 per.name 來獲取值
當我們需要設定值的時候,我們可以采用 set 方法
set name(value) {
this._name = value
}
我們可以直接將屬性定義在 建構式 中,相當于一個語法糖,簡化書寫
constructor(public name: string, public age: number) {}
等價于
name: string,
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
8. 泛型
在定義函式或類時,如果遇到型別不明確時就可以使用泛型
首先我們需要在函式名后面,添加一個 <k> ,用來定義一個泛型 ,這里的 k 是自己隨意取的,可以理解為是一個 k 型別,只有函式執行的時候,我們才知道它具體是什么型別
function fn<k>(a: k): k {
return a
}
我們可以直接條用具有泛型的函式
fn(10)
像這里我們傳入了一個數字 10 ,它會自動推斷出這次的函式呼叫中泛型的型別為 number
但是不是每一次都能自動推斷出型別的,因此我們可以使用 型別斷言
提前告知我們此次傳入的資料型別
fn<string>('hello')
我們也可以指定多個泛型,建議用大寫字母
function fn<k, t>(a: k, b: t): k {
return a
}
fn<string, number>('hello', 1)
指定泛型必須為某一個類
interface Inter {
length: number
}
function fn<T extends Inter > (a:T):number {
return a.length
}
在這里,我們設定了泛型 T 必須是 inter 的實作類,也就是必須有 length 屬性
在類中使用泛型
class MyClass<T> {
name: T
constructor(name: T) {
this.name = name
}
}
學會用 TS 的思維去寫代碼,面向物件
9. 聯合型別
可以設定多個預先型別
let myNumber: string | number
myNumber = 'six'
myNumber = 6
當多個變數有相同型別時,例如 youNumber 變數也需要 string 或者 number 的型別,我們再寫一遍上面的代碼會顯得代碼冗余,我們可以建立一個新的型別
type xNumber = string | number
這樣我們再需要這種聯合型別時,就可以直接使用
let myNumber: xNumber
這就像是介面 interface 一樣,在很多情況下這兩個是可以互換的
10. Utility Types
1. Partial
當我們需要使用一種型別時,但又想里面的引數都是可選時
我們可以采用 partial
type Person = {
name: string,
age: number
}
const myName: Partial<Person> = {age: 20}
全部可選
實作 Partial 原理
type Partial<T> = {
[P in keyof T]?: T[P];
}
怎么理解呢?
首先 T 會接收到一個物件,也就是上面我們傳入的 Person ,從此 T 表示 Person 物件,keyin T 的作用是,將 T 中的 key 值取出來,因此這里得到的是 name 和 age 的一個聯合型別,
再采用 P in XXX 遍歷 物件中的所有鍵,因此左邊就是鍵值了,右邊的 T[P] 得到的就是對應 P 對應的 value 值了,?: 符表示可選型別
2. Omit
洗掉指定型別中的某個型別,這些操作不影響原型別噢
例如我們定義了一個 Person 型別
type Person = {
name: string,
age: number
}
但我們在某個情況使用的時候,需要必須傳遞 age ,name 值可選
我們可以采用 Omit ,第二個引數表示要洗掉的型別
const myName: Omit<Person,'name'> = {age: 20}
實作原理
keyof T 鍵名的聯合型別,K 要洗掉的型別,通過 Exclude 來排除 K ,再通過 Pick 取出剩下的型別
Pick<T, Exclude<keyof T, K>>
3. Pick
從聯合型別中挑選幾個型別
type Person = {
name: string,
age: number
}
const myName: Pick<Person, 'age'> = { age: 20 }
4. Exclude
從聯合型別中洗掉幾個型別
type Person = {
name: string,
age: number
}
const myName: Exclude<Person, 'age'> = { age: 20 } // 報錯
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/305483.html
標籤:其他
上一篇:聊一聊C#與.NET之間的關系
下一篇:Vue快速入門(上)
