typescript学习笔记

2023-12-15 23:40:09
  • js易学即是优点也是缺点

  • ts可以编译成各种版本的js

  • 安装:npm i -g typescript

  • 运行:tsc xxx.ts

  • 变量类型声明:function sum(a:number):number{}

  • 类型

    1. 基本类型:
    • number:表示数值。
    • string:表示字符串。
    • boolean:表示布尔值。
    • nullundefined:表示空值。
    • symbol:表示唯一的符号值。
    1. 复合类型:
    • array:表示数组,可以使用泛型 Array<T> 定义。
      • let a:number[]
      • let a:Array<number>
    • tuple:表示元组,允许你定义一个固定长度和固定类型的数组。
      • 因为固定,所以效率更高。
      • let a:[string, string]
    • object:表示对象类型。
      • 常用于指明对象中包含什么属性。例如:let a:{name:string,age?:number}
      • 加?表示这个属性是可选的
      • 必须存在某个属性其余属性随意 的写法:let a:{name:string,[propName:string]:any}propName:string表示任意字符串形式的的属性名,any表示任意类型
    • function:表示函数类型。
      • 常用于限制函数参数和返回值
      • 写法:let f:(a:number)=>number; f=function(n1){...}
    • enum:表示枚举类型。
      • 枚举就像是一个标签集合,用来给一组特定的事物分配名字。这提高了代码的可读性和可维护性。
      • 使用:
            // Enum
            enum Color {
                Red,
                Green,
                Blue,
                }
        
            //或者显式赋值
            enum Color {
                Red = 0,
                Green = 1,
                Blue = 2,
                }
        
            let color: Color = Color.Red; // 使用枚举成员
            console.log(color); // 输出: 0
            //存在数据库里的就是0而不是Red了
        
    1. 高级类型:
    • any:表示任意类型,取消了类型检查。不写声明类型默认就是any。
    • void:表示没有返回值的函数。
    • never:表示永远不会返回结果的函数。不能返回值。
    • unknown:表示未知类型,相对于 any 更加类型安全。原因:any类型的变量可以赋值给任何变量,会有隐患,unknown类型就不可以。
    • union:表示联合类型,可以包含多种不同类型的值。比如:let a:number|string
    • intersection:表示交叉类型,可以包含多个类型的成员。
    1. 自定义类型:
    • 使用 type 关键字来定义自定义类型。
    • 使用 interface 关键字来定义接口。
    • 字面量类型:比如 let a:10;//a就只能是10。
    1. 补充
    • 或:let b:'male'|'female'; //b就只能赋这两个值
    • 与:let a:{name:string}&{age:number} //等同于{name:string;age:number}
  • 类型断言
    类型断言是一种方式,允许你告诉编译器 “我知道这个变量的类型是什么”,从而可以绕过类型检查器的一些检查。类型断言有两种语法形式:angle-bracket 语法和 as 语法。

    1. Angle-Bracket 语法:
      使用尖括号 <Type> 来进行类型断言,如下所示:
    let someValue: any = "Hello, TypeScript!";
    let strLength: number = (<string>someValue).length;
    

    在这个例子中,我们首先将 someValue 声明为 any 类型,然后使用尖括号 <string> 来告诉 TypeScript 编译器我们将 someValue 视为字符串类型,以便获取其 length 属性。

    1. as 语法:
    let someValue: any = "Hello, TypeScript!";
    let strLength: number = (someValue as string).length;
    

    需要注意的是,类型断言不会改变变量的实际类型,它只是在编译阶段告诉编译器如何处理这个变量。如果类型断言不正确,可能会导致运行时错误。因此,应该谨慎使用类型断言,尽量避免在不确定类型的情况下使用它们,而是更倾向于使用 TypeScript 提供的类型检查功能。

    类型断言在以下情况常常使用:

    • 当你比编译器更了解某个值的类型时,例如在从 DOM 获取元素时。
    • 当你需要与第三方库交互,这些库的类型信息不够完善时。
    • 当你在编写自定义类型声明文件(.d.ts)时,需要告诉 TypeScript 如何处理某个库的类型。
  • 类型别名:

        type ID = number;
        type Point = { x: number; y: number };
        type Person = { name: string; age: number };
    
        // 使用类型别名
        const userId: ID = 123;
        const userLocation: Point = { x: 10, y: 20 };
        const personInfo: Person = { name: "Alice", age: 30 };
    
  • 编译选项

    • tsc xxx.ts -w watch,监视ts文件的变化反映到js上
    • tsc 按照配置文件自动编译所有ts文件
      tsconfig.json 是 TypeScript 项目的配置文件,用于指定
    1. compilerOptions(编译器选项):

      • target: 指定编译后的 JavaScript 版本(如 “ES5”, “ES6” 等)。
      • module: 指定模块的输出格式(如 “CommonJS”, “ES6” 等)。
        • commonJS和ES6的区别
        • c:服务端,被引用的模块会被立即加载
          • 出:a.js: module.exports = {xxx:xxx}
          • 入:const a=require('./a'); a.xxx
        • 6:浏览器端,真正用到了才会加载
          • 出: b.js: export a=xxx
          • 入:import {a} from './b.js'
      • outDir: 指定编译后的 JavaScript 文件的输出目录。
      • rootDir: 指定 TypeScript 文件的根目录。
      • strict: 启用严格类型检查,包括 strictNullChecks, strictFunctionTypes, 等。
      • esModuleInterop: 启用 ES 模块的互操作性。
      • sourceMap: 是否生成源映射文件。
      • declaration: 是否生成声明文件(.d.ts)。
      • allowJs: 允许编译 JavaScript 文件。默认false
      • checkJs: 是否按照ts规则检查js文件语法。默认false
      • noEmit: 不生成编译后的 JavaScript 文件,只进行类型检查。
      • noEmitOnError: 当有错误时,不编译
      • lib:用到了什么库(宿主环境),一般情况下不需要改
    2. includeexclude:

      • include: 包含哪些文件或文件夹进行编译,默认为项目根目录下的所有 TypeScript 文件。例如"./src/**/*"表示src目录下的任意目录(**)的任意文件(*)
      • exclude: 排除哪些文件或文件夹不进行编译,默认为 node_modules, bower_components, jspm_packages 等。
    3. files:

      • 明确指定要包括在编译中的文件列表。
    4. extends:

      • 引用其他 tsconfig.json 文件,当前配置文件会自动包含这个引用文件的配置选项。
    5. compileOnSave:

      • 是否在保存文件时自动触发编译。
    6. typeAcquisition:

      • 自动获取类型声明文件(如从 DefinitelyTyped)。
    7. angularCompilerOptions:

      • 用于 Angular 项目的编译选项。
    8. references:

      • 指定项目依赖关系,允许以多项目的方式构建和编译。
  • webpack打包ts工程文件

      1. 生成package.json配置文件 npm init -y (y:yes,默认选项)
      1. 安装依赖npm i -D webpack webpack-cli typescript ts-loader
      1. 编写webpack.config.js配置文件
      1. 编写package.json在"scripts"中添加"build":"webpack"
      1. 开始打包:npm run build
  • babel的作用
    将最新版本ECMAScript规范(例如ES6、ES7、ES8等)编写的JavaScript代码,转译成可以在不同浏览器中运行的旧版本JavaScript代码。从而实现浏览器兼容。

  • TS中的类:

    1. 类的定义

    在TS中,你可以使用class关键字来定义一个类。例如:

    class Person {
        // 属性
        firstName: string;
        lastName: string;
    
        // 构造函数
        constructor(firstName: string, lastName: string) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    
        // 方法
        getFullName() {
            return `${this.firstName} ${this.lastName}`;
        }
    }
    

    这个类定义了一个Person类,具有firstNamelastName属性以及一个getFullName方法。

    1. 创建类的实例

    一旦类被定义,你可以使用new关键字来创建该类的实例:

    const person = new Person("John", "Doe");
    
    1. 属性和方法

    类中可以包含属性和方法。属性用于存储数据,而方法用于执行操作。在类中的方法可以访问类的属性。

    1. 构造函数

    构造函数用于在创建类的实例时初始化对象的属性。它在对象创建时自动调用。在上面的例子中,constructor方法用于初始化firstNamelastName属性。

    1. 访问修饰符

    TS支持访问修饰符,例如publicprivateprotected,用于控制属性和方法的访问权限。默认情况下,类的成员是public的,这意味着它们可以在类的外部访问。你可以使用访问修饰符来限制成员的访问权限。

    1. 继承

    TS支持类的继承,一个类可以继承另一个类的属性和方法。继承使用extends关键字实现。例如:

    class Employee extends Person {
        employeeId: number;
    
        constructor(firstName: string, lastName: string, employeeId: number) {
            super(firstName, lastName); // 调用父类的构造函数
            this.employeeId = employeeId;
        }
    
        // 可以重写父类的方法
        getFullName() {
            return `${super.getFullName()} (Employee ID: ${this.employeeId})`;
        }
    }
    
    1. 静态属性和方法

    你可以使用static关键字定义静态属性和方法,它们属于类本身而不是类的实例。

    class MathUtility {
        static PI: number = 3.14159;
    
        static calculateCircleArea(radius: number) {
            return MathUtility.PI * radius * radius;
        }
    }
    

    使用方式如下:

    const area = MathUtility.calculateCircleArea(5);
    
    1. 抽象类
      TS支持抽象类,它们不能被实例化,但可以被其他类继承。抽象类通常用于定义基类,其中包含一些共享的属性和方法的框架。

      abstract class Shape {
          abstract getArea(): number;
      }
      

      子类必须实现抽象类中定义的抽象方法。

      这些是 TypeScript 中类的一些基本概念和用法。类是面向对象编程的核心概念之一,可以帮助你更好地组织和抽象代码,使其更易于维护和扩展。

    2. 接口
      在 TypeScript 中,接口(Interfaces)是一种用于定义对象的结构或形状的抽象化工具。接口用于描述对象应该具备的属性和方法,以便在编写代码时进行类型检查,确保对象符合指定的结构。接口在 TypeScript 中非常有用,特别是在面向对象编程和编写可重用代码时。
      以下是关于 TypeScript 接口的一些基本概念和用法:

      1. 接口的定义

      使用 interface 关键字来定义接口。接口描述了一个对象的属性和方法的结构,但不提供实现。例如:

      interface Person {
          firstName: string;
          lastName: string;
          getFullName(): string;
      }
      

      这个 Person 接口定义了一个对象应该包含 firstNamelastName 属性,以及一个 getFullName 方法。

      1. 对象符合接口

      在 TypeScript 中,对象可以符合(或实现)接口,只要对象的结构与接口的结构匹配,就可以将该对象视为符合该接口。例如:

      const person: Person = {
          firstName: "John",
          lastName: "Doe",
          getFullName() {
              return `${this.firstName} ${this.lastName}`;
          }
      };
      

      这个 person 对象符合 Person 接口的结构。

      1. 可选属性

      接口中的属性可以标记为可选,使用 ? 符号。这意味着对象可以包含该属性,也可以不包含。例如:

      interface Car {
          make: string;
          model: string;
          year?: number; // year 是可选属性
      }
      
      const myCar: Car = {
          make: "Toyota",
          model: "Camry"
      };
      
      1. 只读属性

      使用 readonly 关键字可以将接口属性标记为只读,这意味着属性的值在对象创建后不能被修改。例如:

      interface Point {
          readonly x: number;
          readonly y: number;
      }
      
      const point: Point = { x: 10, y: 20 };
      // point.x = 30; // 编译错误,无法修改只读属性
      
      1. 函数类型

      接口可以描述函数类型,包括函数参数和返回值的类型。例如:

      interface CalculateArea {
          (radius: number): number;
      }
      

      这个接口描述了一个函数类型,接受一个 number 类型的参数并返回一个 number 类型的值。

      1. 继承接口

      TypeScript 支持接口之间的继承。一个接口可以继承另一个接口的属性和方法。例如:

      interface Person {
          firstName: string;
          lastName: string;
      }
      
      interface Employee extends Person {
          employeeId: number;
      }
      

      Employee 接口继承了 Person 接口的属性。

      1. 类实现接口

      类可以通过 implements 关键字来实现接口,以确保类符合接口定义的结构。例如:

      class Employee implements Person {
          firstName: string;
          lastName: string;
          employeeId: number;
      
          constructor(firstName: string, lastName: string, employeeId: number) {
              this.firstName = firstName;
              this.lastName = lastName;
              this.employeeId = employeeId;
          }
      
          getFullName() {
              return `${this.firstName} ${this.lastName}`;
          }
      }
      

      Employee 类实现了 Person 接口的结构。

      接口在 TypeScript 中是一种非常有用的工具,它有助于增强代码的可读性和可维护性,同时可以进行静态类型检查,帮助开发者在开发过程中捕获潜在的错误。它们经常用于定义合同和规范,以确保不同部分的代码能够协同工作。

  • this的指向问题:

    在 JavaScript 和 TypeScript 中,构造函数中的 this 关键字的指向是一个重要且常见的概念。理解 this 的指向对于正确编写和理解对象的创建和初始化非常关键。以下是一些关于构造函数中 this 指向的重要概念:

    1. 默认绑定
    • 在普通函数中,this 默认绑定到全局对象(在浏览器中通常是 window 对象),这意味着在全局范围内使用 this 会指向全局对象。
    function sayHello() {
        console.log("Hello, " + this.name);
    }
    
    const name = "Global";
    sayHello(); // 输出 "Hello, Global"
    
    • 在严格模式下,全局对象不会被用作默认绑定,而是 this 会被设置为 undefined
    "use strict";
    
    function sayHello() {
        console.log("Hello, " + this.name);
    }
    
    const name = "Global";
    sayHello(); // 输出 "Hello, undefined"
    
    1. 隐式绑定
    • 当函数作为对象的方法被调用时,this 会隐式绑定到调用该方法的对象。
    const person = {
        name: "John",
        sayHello() {
            console.log("Hello, " + this.name);
        }
    };
    
    person.sayHello(); // 输出 "Hello, John"
    
    1. 显式绑定
    • 你可以使用 call()apply()bind() 方法来显式绑定 this 到指定的对象。
    function sayHello() {
        console.log("Hello, " + this.name);
    }
    
    const person = {
        name: "John"
    };
    
    sayHello.call(person); // 使用 call() 显式绑定
    sayHello.apply(person); // 使用 apply() 显式绑定
    const boundSayHello = sayHello.bind(person); // 使用 bind() 创建绑定的函数
    boundSayHello();
    
    1. 箭头函数中的 this
    • 箭头函数的 this 始终继承自包含它的最近的非箭头函数父作用域。它不具备自己的 this,而是捕获了父作用域的 this 值。
    const person = {
        name: "John",
        sayHello: () => {
            console.log("Hello, " + this.name); // this 指向全局对象,不是 person 对象
        }
    };
    
    person.sayHello(); // 输出 "Hello, undefined"
    
  • 泛型:把类型作为一种参数:

    泛型(Generics)是 TypeScript 中的一个重要特性,它允许你编写可重用的、灵活的代码,同时提高代码的类型安全性。泛型允许你在编写函数、类和接口时,将类型作为参数进行参数化,以便在不同地方使用相同的代码,但可以适用于不同的数据类型。

    以下是有关泛型的基本概念和用法:

    1. 泛型函数

    在函数中使用泛型可以使函数接受不同类型的参数,同时确保正确的类型检查。例如,下面是一个泛型函数,用于交换两个值:

    function swap<T>(a: T, b: T): [T, T] {
        return [b, a];
    }
    
    const result = swap(1, 2); // result 的类型为 [number, number]
    

    在这个示例中,<T> 表示类型参数,它允许我们将不同类型的值传递给 swap 函数,同时保留了类型的一致性。

    1. 泛型类

    你可以创建泛型类,允许类的属性或方法使用泛型类型。例如:

    class Box<T> {
        private value: T;
    
        constructor(value: T) {
            this.value = value;
        }
    
        getValue(): T {
            return this.value;
        }
    }
    
    const numberBox = new Box<number>(42);
    const stringBox = new Box<string>("Hello");
    

    这里的 Box 类是一个泛型类,它可以用不同的类型参数实例化,从而创建不同类型的盒子。

    1. 泛型接口

    泛型也可以用于接口的定义,以便在创建实现该接口的类时指定类型参数。例如:

    interface Pair<T, U> {
        first: T;
        second: U;
    }
    
    const pair: Pair<number, string> = { first: 1, second: "two" };
    

    这个示例中,Pair 接口接受两个类型参数 TU,并且我们可以在使用该接口的时候指定具体的类型。

    1. 泛型约束

    有时候你想要对泛型类型进行一些限制,确保它具有特定的方法或属性。你可以使用泛型约束来实现这一点。例如:

    function lengthOfValue<T extends { length: number }>(value: T): number {
        return value.length;
    }
    
    const strLength = lengthOfValue("Hello"); // 5
    const arrLength = lengthOfValue([1, 2, 3]); // 3
    // const numLength = lengthOfValue(42); // 编译错误,数字没有 length 属性
    

    这里的 <T extends { length: number }> 表示 T 必须是具有 length 属性的对象类型,这样我们可以安全地访问 value.length

    泛型是 TypeScript 中非常强大和灵活的功能,它允许你编写更具通用性和可维护性的代码,并提供了强类型检查,有助于在编译时捕获潜在的错误。通过正确使用泛型,可以提高代码的可读性和可维护性,同时增加代码的复用性。

文章来源:https://blog.csdn.net/weixin_44986776/article/details/135026504
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。