TypeScript筆記

ts 是什么?

  • Typescript 是JavaScript的超集,遵循ES5/ES6規(guī)范,擴(kuò)展了Javascript語法;
  • 越來越多的項(xiàng)目是基于TS,VSCode、Angular6、Vue3、React16;
  • TS提供的類型系統(tǒng)可以幫助我們?cè)趯懘a的時(shí)候提供更豐富的語法提示;
  • 在創(chuàng)建前的編譯階段經(jīng)過類型系統(tǒng)的檢查,就可以避免很多線上的錯(cuò)誤

ts安裝和編譯

npm install  typescript -g
tsc hello.ts
tsc hello.ts hello1.ts hello2.ts

在開發(fā)的過程中,不同文件中出現(xiàn)同變量名是會(huì)出現(xiàn)沖突??梢栽谖募刑砑?/p>

export {}
tsc --init // 生成配置文件tsconfig.json
tsc  // 全局編譯
tsc --watch // 文件改變自動(dòng)編譯

tsconfig.json

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. 指定ECMAScript的目標(biāo)版本*/
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. 指定模塊代碼的生成方式*/
    // "lib": [],                             /* Specify library files to be included in the compilation. 指定編譯的時(shí)候用來包含的編譯文件*/
    // "allowJs": true,                       /* Allow javascript files to be compiled. 允許編譯JS文件*/
    // "checkJs": true,                       /* Report errors in .js files. 在JS中包括錯(cuò)誤*/
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. 指定JSX代碼的生成方式 是保留還是react-native或者react*/
    // "declaration": true,                   /* Generates corresponding '.d.ts' file.生成相應(yīng)的類型聲明文件 */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. 為每個(gè)類型聲明文件生成相應(yīng)的sourcemap*/
    // "sourceMap": true,                     /* Generates corresponding '.map' file. 生成對(duì)應(yīng)的map文件 */
    // "outFile": "./",                       /* Concatenate and emit output to single file. 合并并且把編譯后的內(nèi)容輸出 到一個(gè)文件里*/
    // "outDir": "./",                        /* Redirect output structure to the directory.按原始結(jié)構(gòu)輸出到目標(biāo)目錄 */
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. 指定輸入文件的根目錄,用--outDir來控制輸出的目錄結(jié)構(gòu)*/
    // "composite": true,                     /* Enable project compilation 啟用項(xiàng)目編譯*/
    // "removeComments": true,                /* Do not emit comments to output. 移除注釋*/
    // "noEmit": true,                        /* Do not emit outputs. 不要輸出*/
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. 當(dāng)目標(biāo)是ES5或ES3的時(shí)候提供對(duì)for-of、擴(kuò)展運(yùn)算符和解構(gòu)賦值中對(duì)于迭代器的完整支持*/
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule').r把每一個(gè)文件轉(zhuǎn)譯成一個(gè)單獨(dú)的模塊 */

    /* Strict Type-Checking Options */
    //"strict": true,                           /* Enable all strict type-checking options. 啟用完全的嚴(yán)格類型檢查 */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. 不能使用隱式的any類型*/
    // "strictNullChecks": true,              /* Enable strict null checks. 啟用嚴(yán)格的NULL檢查*/
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. 啟用嚴(yán)格的函數(shù)類型檢查*/
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions.啟用函數(shù)上嚴(yán)格的bind call 和apply方法 */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. 啟用類上初始化屬性檢查*/
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type.在默認(rèn)的any中調(diào)用 this表達(dá)式報(bào)錯(cuò) */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. 在嚴(yán)格模式下解析并且向每個(gè)源文件中發(fā)射use strict*/

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. 有未使用到的本地變量時(shí)報(bào)錯(cuò) */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. 有未使用到的參數(shù)時(shí)報(bào)錯(cuò)*/
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. 當(dāng)不是所有的代碼路徑都有返回值的時(shí)候報(bào)錯(cuò)*/
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. 在switch表達(dá)式中沒有替代的case會(huì)報(bào)錯(cuò) */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). 指定模塊的解析策略 node classic*/
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. 在解析非絕對(duì)路徑模塊名的時(shí)候的基準(zhǔn)路徑*/
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. 一些路徑的集合*/
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. 根目錄的列表,在運(yùn)行時(shí)用來合并內(nèi)容*/
    // "typeRoots": [],                       /* List of folders to include type definitions from. 用來包含類型聲明的文件夾列表*/
    // "types": [],                           /* Type declaration files to be included in compilation.在編譯的時(shí)候被包含的類型聲明 */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking.當(dāng)沒有默認(rèn)導(dǎo)出的時(shí)候允許默認(rèn)導(dǎo)入,這個(gè)在代碼執(zhí)行的時(shí)候沒有作用,只是在類型檢查的時(shí)候生效 */
    //"esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.*/
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks.不要symlinks解析的真正路徑 */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. 指定ts文件位置*/
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. 指定 map文件存放的位置 */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. 源文件和sourcemap 文件在同一文件中,而不是把map文件放在一個(gè)單獨(dú)的文件里*/
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. 源文件和sourcemap 文件在同一文件中*/

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. 啟動(dòng)裝飾器*/
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  }
}

ts數(shù)據(jù)類型

  1. 任意類型(any): 聲明為 any 的變量可以賦予任意類型的值;
let b:any = 1;
  • any就是可以賦值給任意類型
  • 第三方庫沒有提供類型文件時(shí)可以使用any
  • 類型轉(zhuǎn)換遇到困難時(shí)
  • 數(shù)據(jù)結(jié)構(gòu)太復(fù)雜難以定義
  1. 數(shù)字類型(number)
let age:number = 18;
  1. 字符串類型(string)
let name: string = 'cc'
  1. 布爾類型(boolean)
let flag: boolean = true
  1. 數(shù)組類型(array)
// 在元素類型后面加上[]
let arr: number[] = [1, 2, 3]

// 使用數(shù)組泛型
let arr: Array<number> = [1, 2, 3]
  1. 元組類型(tuple): 元組類型用來表示已知元素?cái)?shù)量和類型的數(shù)組,各元素的類型不必相同,對(duì)應(yīng)位置的類型需要相同。
let p: [string, age] = ['cc', 18]

元組 vs 數(shù)組

元組 數(shù)組
每一項(xiàng)可以是不同的類型 每一項(xiàng)都是同一種類型
有預(yù)定義的長(zhǎng)度 沒有長(zhǎng)度限制
用于表示一個(gè)固定的結(jié)構(gòu) 用于表示一個(gè)列表
  1. 枚舉類型(enum):枚舉類型用于定義數(shù)值集合;默認(rèn)情況下,從0開始為元素編號(hào)。也可手動(dòng)修改指定成員的數(shù)值。
enum Color { Red, Green, Blue };
let c: Color = Color.Blue;
console.log(c);    // 輸出 2
  1. void:用于標(biāo)識(shí)方法返回值的類型,表示該方法沒有返回值
function hello(name: string):void {
    console.log(`hello, ${name}`)
}

注:

  • 當(dāng)我們聲明一個(gè)變量類型是 void 的時(shí)候,它的非嚴(yán)格模式(strictNullChecks:false)下僅可以被賦值為 null 和 undefined;
  • 嚴(yán)格模式(strictNullChecks:true)下只能返回undefined
  1. null 和 undefined
  • null 和 undefined 是其它類型的子類型,可以賦值給其它類型
  • 嚴(yán)格模式(strictNullChecks:true)下不屬于任何一個(gè)類型,只能賦值給自己這種類型或者any
// 非嚴(yán)格
let a: number;
a = null
a = undefined

// 嚴(yán)格
let b: number | undefined | null;
b = 1;
b = null;
b = undefined;
  1. never:never 是其它類型(包括 null 和 undefined)的子類型,代表從不會(huì)出現(xiàn)的值。
  • 拋出異常的情況
  • 無限循環(huán)的情況

never 和 void 的區(qū)別?

  • void 可以被賦值為 null 和 undefined的類型。 never 則是一個(gè)不包含值的類型
  • 擁有 void 返回值類型的函數(shù)能正常運(yùn)行。擁有 never 返回值類型的函數(shù)無法正常返回,無法終止,或會(huì)拋出異常。

ts變量聲明

  1. 聯(lián)合類型(Union Types): 表示取值可以為多種類型中的一種。
    注:在未賦值時(shí)聯(lián)合類型上只能訪問兩個(gè)類型共有的屬性和方法。
let ss: string | number;
// 在這里只能獲取 string 和 number 類型的共有屬性和方法
if (typeof ss === 'string') {
    // 可以獲取字符串的屬性和方法
} else {
     // 可以獲取數(shù)值的屬性和方法
}
  1. 類型斷言(Type Assertion): 類型斷言可以用來手動(dòng)指定一個(gè)值的類型,即允許變量從一種類型更改為另一種類型。

程序員 強(qiáng)行告訴ts是一個(gè)什么類型。

    // <類型>值
    let str:string = '1'
    let str1:number = <number> <any> str
    console.log(str1)

    // 值 as 類型
    let ss: string | number;
    let s = (ss as string).length;
    let n = (ss as number).toFixed(2);
  • 當(dāng) S 類型是 T 類型的子集,或者 T 類型是 S 類型的子集時(shí),S 能被成功斷言成 S。
  • 當(dāng)你在TypeScript里使用JSX時(shí),只有 as 語法斷言是被允許的。
  1. 類型推斷:當(dāng)類型沒有給出時(shí),ts 編譯器利用類型推斷來推斷類型。
  • 定義時(shí)未賦值就會(huì)被推斷成any類型
  • 定義時(shí)賦值就能利用類型推斷出類型
let s; // 定義時(shí)未賦值,推斷成any
s = 1;
s = '1';

let num = 1 // 定義賦值,類型推斷為 number;
num = '1' // 再次賦值就會(huì)編譯錯(cuò)誤
  1. 字面量類型: 可以把字符串、數(shù)字、布爾值字面量組成一個(gè)聯(lián)合類型
type cType = 1 | '1' | true
let c: cType = 1  // 變量c 為 1 '1' true 三者之一
  1. 交叉類型:將多個(gè)類型合并為一個(gè)類型。它包含了所有類型的特性。
interface Person {
    id: string,
    name: string
}

interface Master {
    age: number
}

type Staff = Person & Master

const staff: Staff = {
    id: '007',
    name: 'cc',
    age: 10
}

函數(shù)

  1. ts函數(shù) vs js函數(shù)
TypeScript JavaScript
含有類型 無類型
箭頭函數(shù) 箭頭函數(shù)(ES2015)
函數(shù)類型 無函數(shù)類型
必填和可選參數(shù) 所有參數(shù)都是可選的
默認(rèn)參數(shù) 默認(rèn)參數(shù)
剩余參數(shù) 剩余參數(shù)
函數(shù)重載 無函數(shù)重載
  1. 函數(shù)的定義: 可以指定參數(shù)的類型和返回值的類型
function sayName(name: string): string {
    return `hello, ${name}`
}
  1. 函數(shù)表達(dá)式
// 定義一個(gè)類型,用來約束函數(shù)表達(dá)式
type info = (name: string, age: number) => string;
let p: info = function(name: string, age: number): string {
    return `hi, my name is ${name}, I'am ${age} years old`
}
p('cc', 19)
  1. 函數(shù)調(diào)用
    實(shí)參的類型和個(gè)數(shù)必須和形參一一對(duì)應(yīng)

  2. 可選參數(shù)
    可選參數(shù)必須是最后一個(gè)參數(shù)。

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + lastName
    }
    return firstName
}

buildName('c')
buildName('c', 'pc')
  1. 默認(rèn)參數(shù)
function person(name: string, age:number = 18): void {
    console.log(age)
}
  1. 剩余參數(shù)
function sum(...numbers:number[]) {
    return numbers.reduce((val,item)=>val+=item,0);
}
  1. 重載是方法名字相同,而參數(shù)數(shù)量或者類型不同,返回類型可以相同也可以不同。
// 為一個(gè)函數(shù)提供多個(gè)函數(shù)定義
function double(v: number): number; // 函數(shù)聲明
function double(v: string): string; // 函數(shù)聲明
function double(v: any): any { // 函數(shù)的實(shí)現(xiàn),必須緊跟在函數(shù)聲明后面
    if (typeof v === 'number') return v * 2
    if (typeof v === 'string') return v + v
}

  1. 定義類
  • "strictPropertyInitialization": true // 啟用類屬性初始化的嚴(yán)格檢查
  • 屬性初始化并賦值;greeting: string = 'cc';
  • 添加constructor(greeting: string) { this.greeting = greeting }
  • greeting!: string;
class Greeter {
    greeting: string;
    constructor(greeting: string) {
        this.greeting = greeting
    }
    greet(): string {
        return 'Hello, ' + this.greeting; // this 表示的是類的成員
    }
}

let greeter = new Greeter('cc')

public 可以省略

class Greeter {
    constructor(public greeting: string) {}
}
  1. readonly
  • readonly 修飾的變量只能在構(gòu)造函數(shù)中初始化
  • readonly 只是在編譯階段進(jìn)行代碼檢查。而 const 在運(yùn)行時(shí)檢查
class Person {
    public readonly name: string;
    constructor(name: string) {
        this.name = name
    }
}

let p = new Person('cc')
// p.name = 'yy'
  1. 修飾符
  • puclic: 自己、子類、其他都可以訪問
  • protected: 自己和子類可以訪問,其他不能訪問
  • private: 只能自己訪問,子類和其他不能訪問
class Father {
  public readonly name: string = 'dad';
  protected age: number = 10;
  private money: number = 10000;
}

class Son extends Father {
  getName(): void {
    console.log(this.name)
  }

  getAge(): void {
    console.log(this.age)
  }

  // getMoney(): void {
  //   console.log(this.money) // money 為私有屬性
  // }
}
  1. 類的繼承 extends
  • 一次只能繼承一個(gè)類,不支持繼承多個(gè)類,但 TypeScript 支持多重繼承(A 繼承 B,B 繼承 C)
  • 繼承:子類繼承父類,子類除了擁有父類的所有特性外,還有一些更具體的特性
  • 多態(tài):由繼承而產(chǎn)生了相關(guān)的不同的類,對(duì)同一個(gè)方法可以有不同的行為
  1. 類的靜態(tài)屬性和靜態(tài)方法 static

  2. 抽象類abstract

  • 抽象類是行為的抽象,一般來封裝一些公共屬性和方法
  • 無法被實(shí)例化,只能被繼承
  • 抽象方法不能在抽象類中實(shí)現(xiàn),只能在抽象類的具體子類中實(shí)現(xiàn),而且必須實(shí)現(xiàn)
abstract class Person {
  name!:string;
  abstract say():void;
}

class Man extends Person {
  say():void {
    console.log('Nice!')
  }
}
  • 接口里的方法都是抽象的
  • 實(shí)現(xiàn)接口 implements
  • 一個(gè)類只能繼承一個(gè)父類,但是可以實(shí)現(xiàn)多個(gè)接口
interface Runing {
    run(): void;
}

interface Eating {
    eat(): void;
}

class Man extends Person implements Runing, Eating {
  say(): void {}
  run(): void {}
  eat(): void {}
}
  1. 重寫
  • 重寫:子類重寫繼承自父類中的方法
  • 重載:為同一個(gè)函數(shù)提供多個(gè)類型定義

接口

  • 接口一方面可以在面向?qū)ο缶幊讨斜硎緸?code>行為的抽象,另外可以用來描述對(duì)象的形狀
  • 接口就是把一些類中共有的屬性和方法抽象出來,可以用來約束實(shí)現(xiàn)此接口的類
  1. 定義接口
//接口可以用來描述`對(duì)象的形狀`,少屬性或者多屬性都會(huì)報(bào)錯(cuò)
interface Speakable{
    speak(): void;
    name?: string; // ?表示可選屬性
}

let speakman:Speakable = {
  speak() {},//少屬性會(huì)報(bào)錯(cuò)
  name: 'cc',
  // age: 1//多屬性也會(huì)報(bào)錯(cuò)
}
  1. 任意屬性
// 無法預(yù)先知道有哪些新的屬性的時(shí)候,可以使用 `[propName:string]: any`,propName名字是任意的
interface Person {
  readonly id: number;
  name: string;
  [propName: string]: any;
}
  1. 接口的繼承 extends
  2. 函數(shù)類型接口:對(duì)方法傳入的參數(shù)和返回值進(jìn)行約束
interface computedAge {
    (birth: number): number
}

let getAge: computedAge = function(birth: number): number {
    return 2020 - birth
}
interface sumInterface {
  (...args: number[]): number
}

let sum: sumInterface = (...args: number[]): number {
  return args.reduce((a, b) => a + b, 0)
}
  1. 可索引接口:對(duì)數(shù)組或者對(duì)象進(jìn)行約束
interface Interface1 {
    [index: number]: string
}

interface Interface2 {
    [index: string]: string
}

泛型

  • 軟件工程中,我們不僅要?jiǎng)?chuàng)建一致的定義良好的API,同時(shí)也要考慮可重用性。組件不僅能夠支持當(dāng)前的數(shù)據(jù)類型,同時(shí)也能支持未來的數(shù)據(jù)類型,這在創(chuàng)建大型系統(tǒng)時(shí)為你提供了十分靈活的功能。
  • 泛型(Generics)是指在定義函數(shù)、接口或類的時(shí)候,不預(yù)先指定具體的類型,而在使用的時(shí)候再指定類型的一種特性
  • 設(shè)計(jì)泛型的關(guān)鍵目的是在成員之間提供有意義的約束,這些成員可以是:類的實(shí)例成員、類的方法、函數(shù)參數(shù)和函數(shù)返回值。
  1. 泛型類 用到了泛型的類
class CustomerGeneric<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}
 
  1. 泛型接口
interface Point<A, B> {
  a: A;
  b: B;
}

function point<A, B> (a: A, b: B): Point<A, B> {
  return { a, b }
}

point(1, 3)

  1. 泛型參數(shù)默認(rèn)類型
interface A<T=string> {
    name: T;
}

let sa = { name: 'cc' }
let na = { name: 18 }
  1. 泛型的約束
interface LengthWise {
  length: number
}

function logger<T extends LengthWise>(val: T) {
  console.log(val.length) // 可以獲取length屬性
}
  1. 泛型工具類型

5.1 Partial:將某個(gè)類型里的屬性全部變?yōu)榭蛇x項(xiàng) ?

type Partial<T> = {
    [P in keyof T]?: T[P];
};

5.2 Required: 將傳入的屬性中的可選項(xiàng)變?yōu)楸剡x項(xiàng)

type Required<T> = { [P in keyof T]-?: T[P] };

5.3 Readonly:通過為傳入的屬性每一項(xiàng)都加上 readonly 修飾符來實(shí)現(xiàn)

type Readonly<T> = { readonly [P in keyof T]: T[P] }

5.4 Pick: 能夠幫助我們從傳入的屬性中摘取某一項(xiàng)返回

type Pick<T, K extends keyof T> = { [P in K]: T[P] };

5.5 Exclude: 將某個(gè)類型中屬于另一個(gè)的類型移除掉

type Exclude<T, U> = T extends U ? never : T;

5.6 Record: 將 K 中所有的屬性的值轉(zhuǎn)化為 T 類型

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
  1. 一些常見泛型變量代表的意思:
  • T(Type):表示一個(gè) TypeScript 類型
  • K(Key):表示對(duì)象中的鍵類型
  • V(Value):表示對(duì)象中的值類型
  • E(Element):表示元素類型

類型變換

  1. 交叉類型: 把多個(gè)類型合并成一個(gè)大的總類型
interface Bird {
  name: string
  fly(): void
}

interface Person {
  age: number;
  talk(): void;
}

type BirdMan = Bird & Person

  1. typeof:獲取一個(gè)變量的類型;

先拿到一個(gè)對(duì)象,然后通過對(duì)象獲取,反推這個(gè)對(duì)象的類型

let p = { name: 'cc', age: 18 }
type Person = typeof p

let p1: Person = { name: 'yy', age: 17 }
  1. 索引訪問操作符
interface Person {
    location: {
        city: string
    }
}

let p: Person['location'] = { city: 'beijing' }
  1. keyof 操作符可以用來一個(gè)對(duì)象中的所有 key 值
interface Person {
    name: string;
    age: number;
}

type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" 
type K3 = keyof { [x: string]: Person };  // string | number
  1. 批量操作
interface Person {
    name: string;
    age: number
}

type PersonType = {
    [key in keyof Person]?: Person[key] // 批量將參數(shù)變成可選參數(shù)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容