typescript学习笔记 分享 待更新

122 阅读11分钟

一、Typescript手册

1.1 基础类型

1.1 静态类型

// 数组类型
let person: string[] = ['zhangsan', 'lisi', 'wangwu', 'zhaoliu']

// 对象类型
let person1: {
  name: string
  age: number
} = {
  name: 'zhangsan',
  age: 18,
}

// 类类型
class Person {}
let person2: Person = new Person()

// 函数类型
const person3: () => string 
= () => 'zhangsan'

1.2 类型推断

// 数组类型推断
let a = ['zhangsan', 'lisi', 'wangwu']

// 自动推导
let c = 1

// 对象自动推导
let person4 = {
  name: 'zhangsan',
  age: 18,
}

1.3 函数参数

// 函数类型
const demo1 = (one: number, two: number): number => one + two
const b = demo1(1, 2)

// 函数参数为对象类型
const demo2 = ({ one, two }: { one: number; two: number }) => one + two
demo2({ one: 1, two: 2 })

1.4 数组类型注解

const numberArr: number[] = [1, 2, 3, 4]

const stringArr: string[] = ['zhangsan', 'lisi']

const anyArr = ['123', 1, { name: 'zhangsan', age: 18 }]

// 类型是数组中嵌套对象
// 1、第一种写法
const persons: { name: string; age: number }[] = [{ name: 'zhangsan', age: 18 }]

// 2、第二种写法
class Persons {
  name: string
  age: number
}
const persons1: Persons[] = [{ name: 'zhangsan', age: 18 }]

// 3、第三种写法
type male = { name: string; age: number }

const persons2: male[] = [{ name: 'zhangsan', age: 18 }]

1.5 元组

// 字符串和数字类型数组
const person5: (string | number)[] = ['zhangsan', 18]

// 元组 (严谨:必须按照类型顺序填写对应的数据)
const person6: [string, number] = ['zhangsan', 18]

// 元组数组
const person7: [string, number][] = [
  ['zhangsan', 18],
  ['lisi', 18],
  ['wangwu', 18],
]

1.2 变量声明

1.3 接口

1.3.1 可选属性

interface SquareConfig {
    color?: string
    width?: number
}

function createSquare(config: SquareConfig) {
    let newSquare = { color: "white", area: 100 };
    if (config.color) {
        newSquare.color = config.color;
    }

    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare
}

let mySquare = createSquare({color: "black"});
console.log(mySquare);

1.3.2 只读属性

interface Point {
    readonly x: number;
    readonly y: number
}

let p1: Point = { x: 1, y: 2 };
p1.x = 10;     // 报错

1.3.3 额外的属性检查

1、类型断言

interface SquareConfig {
    color?: string;
    width?: number;
}

// colour 不属于 SquareConfig,会报错, 可以使用类型断言
let mySquare = createSquare({ opacity: 0.5, width: 100 } as SquareConfig);

2、添加字符串索引签名

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

let mySquare = createSquare({ opacity: 0.5, width: 100 });

1.3.4 可索引的类型

任意个数键为 key, 值为value的属性

// key为 数值类型, value 为字符串类型
interface StringArray {
    [index: number]: string
}
let strArr1: StringArray = { 0: "Bob", 1: "Fred" }
let strArr2: StringArray = ["Bob", "Fred"]

// key为 字符串类型, value为字符串类型
interface Person {
    [ propName: string ] : string
}

let p1:Person = {
    name: "zhangsan",
    height: "1.8",
    sex: "nan"
}

1.3.5 函数类型

interface Iter {
    func: (a: number, b: number) => void
}

const a: Iter = {
    func: (a: number, b: number) => {
        console.log(a, b);
    }
}

// 测试
a.func("wdq","dwq");

1.4 类

7.1 类的基本使用

class person {
  content = 'hello world'
  sayHello() {
    return this.content
  }
}

class persons extends person {
  sayHello() {
    // super指向了父类
    return super.sayHello() + '你好'
  }
  sayHi() {
    return 'hi world'
  }
}

// 测试
const people = new persons()

console.log('people.sayHi(): ', people.sayHi())
console.log('people.sayHello(): ', people.sayHello())

7.2 类的访问类型

// public 公共的属性或方法
// protected 受保护的的属性或方法 ,继承的类可以访问到
// private 只能在类的内部进行使用

class Person {
  public content: string = 'hello world'
  protected sayHello() {
    return this.content
  }
}

class Persons extends Person {
  sayHi() {
    return 'hi world'
  }
}

// 测试
const people2 = new Persons()
people2.content = 'zhangsan'
console.log('people2.sayHi(): ', people2.sayHi())

7.3 类的构造类型

class Person2 {
  constructor(public name: string) {}
}

class Persons2 extends Person2 {
  constructor(public age: number) {
    super('zhangsan')
  }
}

// 测试
const people3 = new Persons2(18)
console.log(people3.age)
console.log(people3.name)

7.4 getter和setter

class PerSon {
  constructor(public _name: string) {}
  get name() {
    return this._name
  }
  set name(_name: string) {
    this._name = 'zhangsan'
  }
}

// 测试
const zhangsan = new PerSon('lisi')
console.log(zhangsan)

7.5 static

class PerSon1 {
  static sayHello() {
    return 'hello world'
  }
}

// 测试
console.log(PerSon1.sayHello())

7.6 只读属性和抽样类

// 抽象类
abstract class Girl {
  abstract run()
}

class demo extends Girl {
  run() {
    return '跑'
  }
}

// 只读属性
class demo1 {
  public readonly _name: string
  constructor(name: string) {
    this._name = name
  }
}

// 测试
const test = new demo1('zhangsan')
console.log(test._name)

7.7 构造签名

// new (x: number, y: number) 被称为构造签名
interface Point {
    new(x: number, y: number): Point; // 构造函数的参数类型
    x: number;
    y: number;
}


class Point2D implements Point {
    readonly x: number;
    readonly y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

1.5 函数

1.5.1 函数返回值是元组

1.5.2 返回多种函数类型

interface FactoryType {
    (a?: any, b?: string): string;
    (a?: number, b?: string, c?: number): string;
}

function factory(): FactoryType {
    return function (a?: number, b?: string, c?: number) {
        return "fqwjklhfklqw";
    };
}

1.6 泛型

1.6.1 函数泛型

1.6.1.1 普通函数

function createArr<T>(length: number, value: T): Array<T> {
    let arr = []
    for (var i = 0; i < length; i++) {
    arr[i] = value
    }
    return arr
}

1.6.1.2 箭头函数

const createArr = <T>(length: number, value: T): Array<T> => {
  let arr = []
  for (var i = 0; i < length; i++) {
    arr[i] = value
  }
  return arr
}

// 在调用的时候指定T为string类型
const stringArr: Array<string> = createArr<string>(10, '2')
// 如果在调用得时候也不指定类型那么会自动推到
// 因为1是number所以推出T为number,那么返回值也是number数组,如果使用其他类型数组接收返回值,会报错
const numberArr: Array<number> = createArr(3, 1)

1.6.2 泛型类

1.7 枚举

// 使用时 BussinessStatus.CODE_SUCCESS
export enum BussinessStatus {
    CODE_SUCCESS = 200,
    WARN_TIP = 400,
    SYSTEM_EXCEPTION = 500,
    LOGIN_FAILURE = 600,
    LOGIN_FAILED = 700,
}

1.8 类型推论

1.8.1 自动推断

没有指出具体类型,ts会自动推断类型

let x = 1;  // 推断为number

1.8.2 最佳通用类型

// number | null
let x = [0, 1, null];

// 类型推断的结果为联合数组类型
let zoo = [new Rhino(), new Elephant(), new Snake()]; // (Rhino | Elephant | Snake)[]
// 当候选类型不能使用的时候我们需要明确的指出类型
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];

1.8.3 上下文类型

TypeScript类型检查器使用Window.onmousedown函数的类型来推断右边函数表达式的类型。 因此,就能推断出 mouseEvent参数的类型了。

window.onmousedown = function(mouseEvent) {
    console.log(mouseEvent.button);  //<- Error
};

如果上下文类型表达式包含了明确的类型信息,上下文的类型被忽略。 重写上面的例子:

window.onmousedown = function(mouseEvent: any) {
    console.log(mouseEvent.button);  //<- Now, no error is given
};

1.9 类型兼容性

1.10 高级类型

1.10.1 交叉类型

1.10.2 联合类型

1.10.3 类型保护与区分类型

1.10.4 类型别名

typeof 可以获取一个具体值的类型

1.10.4.1 typeof与函数结合使用

function add(a: number, b: number): number {
    return a + b;
};

type t1 = typeof add;
let test: t1 = function (a: number, b: number): number {
    return 1
};

1.10.4.2 typeof与类结合使用

class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
};

// 这里 typeof Point 等价于  new (x: number, y: number) => number;
function getInstance(PointClass: typeof Point, x: number, y: number) {
    return new PointClass(x, y);
}

function getInstance2(PointClass: Point, x: number, y: number) {
    return new PointClass(x, y); // 报错 此表达式不可构造。类型 "Ponit" 没有构造签名。
}

1.10.4.3 typeof和function结合使用

function run(maybeArgv?: Array<string>, project?: Config.Path): Promise<void>;

const default = {
    run: typeof run;  //  等价于 (maybeArgv?: Array<string>, project?: Config.Path) => Promise<void>;
}

1.11 三斜线指令

三斜线指令是一种特殊的注释语法,用于在TypeScript文件中引入外部模块或库的声明文件。

///

其中,path/to/file.d.ts是声明文件的路径。通过使用三斜线指令,我们可以告诉编译器在编译过程中引入指定的声明文件,以便在代码中使用相关的类型定义和接口。

需要注意的是,从TypeScript 2.0版本开始,推荐使用ES6模块语法(importexport)来引入外部模块,而不是使用三斜线指令。三斜线指令主要用于旧版的TypeScript项目或需要与其他工具(如JSDoc)进行集成的情况下使用。

例如:

// 表明这个文件使用@types/node/index.d.ts里面声明的名字
/// <reference types="node">;

1.12 关键字

1.12.1 keyof关键字

获取类型中所有键值 作为 类型

type Person = {
    name: string,
    age: number,
    gender: string
}

type PersonKeys = keyof Person;  // 类型为 "name" | "age" | "gender";
let test1: PersonKeys = "name";
let test2: PersonKeys = "age";
let test3: PersonKeys = "sex";

1.12.2 infer关键字

infer关键字用于提取类型中的信息。当我们定义一个泛型类型或条件类型时,infer用于提取类型变量的实际类型。

对于条件类型,infer通常与extends关键字一起使用

// Str 类型是以空格后跟其他字符串开始,Rest类型为Hello World
// 例如: TrimLeft<" hello">, 条件Str entends ` ${infer Rest}`的结果将是Rest类型为 "hello";
type TrimLeft<Str extends string> = Str extends ` ${infer Rest}` ? TrimLeft<Rest> : Str;
type TrimRight<Str extends string> = Str extends `${infer Rest} ` ? TrimRight<Rest> : Str;
type Trim<Str extends string> = TrimLeft<TrimRight<Str>>;

type T2 = Trim<'    Hello World   '>;

const str: T2 = "Hello World"
console.log(str);

1.13 any、unknown、never和void

any:任意类型的变量

unknown: 表示未知类型 unknown与any类似 但使用前必须进行断言或守卫

never:永不存在的值的类型

void: 无任何类型,没有类型 用于函数时,never表示函数用于执行不到返回值那一步(抛出异常或死循环)的返回值类型 即永不存在的值的类型。 而void则表示没有返回值,不返回或返回undefined

1.13.2 unknow

不允许直接使用 unknow 变量,需要将该变量强制转换为已知类型或收窄其类型

const x: unknow = {
    a: "a-value",
    b: "b-value"
}

(x as {a: string, b: string}).a;

1.14 模块添加声明

添加模块声明之后需要自己编写类型模块,否测找不到对应类型提示

第三方类库没有 *.d.ts 文件,需要在项目跟目录下添加 types/index.d.ts文件,在文件中声明模块

1.15 常用泛型类型

1.15.1 获取函数返回值

function test() {
    return "string";
}

type ReturnType1 = ReturnType<typeof test>;

1.15.2

interface MainType {
    name: string,
    age: number
}

type NestedType = MainType & {
    isDeveloper: boolean
}

type Preffity<T> = {
    [K in keyof T]: T[K]
} & {}

type idk = Preffity<NestedType>

1.15.3 可选参数,必填参数

interface Todo {
    title: string,
    description: string
}

const updateTodo = (todo: Todo, filedsToUpdate: Partial<Todo>) => {
    return { ...todo, filedsToUpdate };
}

const initTodo: Todo = {
    title: "stirng",
    description: "string"
}

updateTodo(initTodo, {})


// 大体实现
// Partial 将接口类型参数变为可选
// 大体实现
// type Partial1<T> = {
//     [K in keyof T]?: T[K]
// }

// Required 将接口类型参数变为必填
// type Required1<T> = {
//     [K in keyof T]-?: T[K];
// };

1.15.4 省略多个属性

interface Test {
    name: string,
    age: number,
    createAt: Date
}

const t: Omit<Test, "name" | "age" | "createAt"> = {}

type aaa = {
    kind: "circle",
    name: string
} | {
    kind: "square",
    x: number
}

type b = Exclude<aaa, { kind: "circle" } | { kind: "squre" }>

1.15.5 定义对象

const map: Record<string, string> = {};


// Record类型源码
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

1.15.6 函数第二个参数根据第一个参数类型变化

interface Attributes {
    a: string;
    b: string;
    c: CType
}


interface CType {
    name: string;
    age: number
}


function test1<K extends keyof Attributes>(param1: K, param2: Attributes[K]) {
    const _this: Attributes = {
        a: "1",
        b: "2",
        c: {
            name: "string",
            age: 1
        }
    };

    _this[param1] = param2;

    return _this;
}


// 测试
console.log(test1("c", { name: "1", age: 1 }));

二、Typescript配置

2.1 compilerOptions配置

{
    "compilerOptions": {
      /* 基本选项 */
      "target": "es5",                       // 指定 ECMAScript 目标版本:  'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'esnext'
      "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' ,'ES6','es2022',or 'esnext'
      "lib": [],                             // 指定要包含在编译中的库文件,也就是库的声明文件用于代码提示,
                                             //当你用三方库(例如polyfills)实现了高版本js的部分写法,但又不是全部(所以不能直接指定target为高版本)

      "allowJs": true,                       // 允许编译 javascript 文件,在js文件中可以有d.ts/ts文件的类型提示
      "checkJs": true,                       // 报告 javascript 文件中的错误
      "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
      "declaration": true,                   // 生成相应的 '.d.ts' 文件
      "sourceMap": true,                     // 生成相应的 '.map' 文件
      "outFile": "./",                       // 将输出文件合并为一个文件
      "outDir": "./",                        // 指定输出目录
      "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
      "removeComments": true,                // 删除编译后的所有的注释
      "noEmit": true,                        // 不生成输出文件
      "importHelpers": true,                 // 从 tslib 导入辅助工具函数
      "isolatedModules": true,               // 将每个文件作为单独的模块 (与 'ts.transpileModule' 类似).
 
      /* 严格的类型检查选项 */
      "strict": true,                        // 启用所有严格类型检查选项
      "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
      "strictNullChecks": true,              // 启用严格的 null 检查
      "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
      "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
 
      /* 额外的检查 */
      "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
      "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
      "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
      "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
      "skipLibCheck": true,                  // 跳过所有声明文件的类型检查
      "skipDefaultLibCheck": true,           //只跳过默认声明文件的类型检查,也就是忽略检查带有/// <reference no-default-lib=“true”/>的文件。
 
      /* 模块解析选项 */
      "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
      "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
      "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
      "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
      "typeRoots": [],                       // 指定类型文件包所在的文件夹(文件夹下有多个包),未设置默认@types,
                                             // 与types不同的是,typeRoots指定包所在的文件夹,types指定单个包,
                                             // 只支持使用相对路径(./xxx/xxx)引用,文件夹下存在单文件无效,仅支持包。
                                             // 包也是一个文件夹,包根目录有设置过types选项的package.json文件,或index.ts/index.d.ts文件

      "types": [],                           // 需要包含的类型声明文件,未设置默认typeRoots指定文件夹下的所有包,设置后则仅按指定的包。
                                             // 写法(xxx或xxx/xxx)优先在typeRoots 指定的包集合中下查找指定的包,如果没有就查找node_modules下的包,
                                             // 如果设置了typeRoots,但是并未指定@types,那在最后还会查找一次@types。
                                             // 写法(./xxx/xxx)相对tsc onfig.json的路径查找包,
                                             //优先级 名称.d.ts > 名称/package.json的types设置> 名称/index.d.ts

      "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。
 
      /* Source Map Options */
      "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
      "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
      "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
      "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
 
      /* 其他选项 */
      "experimentalDecorators": true,        // 启用装饰器
      "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
    }
}