美文网首页
TypeScript记录

TypeScript记录

作者: cs0710 | 来源:发表于2020-04-02 14:47 被阅读0次

    使用场景: 大型项目或者多人协作

    优点:提高开发效率,提高项目健壮性

    TS vs JS

    • 是JS的超集,遵循JS的语法和语义,最终编译为原生JS
    • 跨平台且开源
    • 可以重用JS,并且可以无缝使用JS的流行的库(如需要使用,则要tsconfig.json配置文件中开启allowJs: true)
    • TS提供了类、接口和泛型的概念,更易于开发和维护
    • 前端三大框架均支持TS语言环境

    01.Typescript开发构建和调试

    // 安装前置依赖包
    
    // 安装ts
    npm i typescript -g
    
    // 查看typescript安装的版本, @3.8.3
    tsc -v
    
    // 一般解决第三方模块文件声明问题
    npm i @types/node -D
    
    // 创建tsconfig.json配置文件
    tsc --init
    
    // 编译对应的文件
    tsc test.ts
    

    以vscode编辑器为例,这里打开终端--运行任务,选择tsc watch -tsconfig.json,自动监视ts文件的改动并编译为js文件到指定输出目录(修改tsconfig.json, "outDir": "./jsFile"即可),对编译后的js文件使用nodemon xxx.js即可运行编译后文件

    如需引入第三方组件,则需要安装第三方组件的TS依赖或者自己别写x.d.ts第三方声明,同时也可以通过@ts-ignore不对其进行TS检查

    02.Typescript变量类型

    TS类型共13种

    • undefined
    • null空类型
    • string字符串类型
    • number数值类型
    • boolean布尔类型
    • enum枚举类型
    • array数组类型
    • tuple元组类型
    • void空类型
    • any任意类型
    • never
    • object
    • 类型断
    字符串
    // 1. 字符串
    const str: string = 'wangcai';
    
    const intro = `
      你好,
      我是${str}
    `;
    console.log(intro);
    
    数值和布尔
    //2. 数字
    const num1: number = 16; // 十进制
    const num2: number = 0x10; // 16进制
    const num3: number = 0o20; // 8进制
    const num4: number = 0b10000; // 2进制
    console.log(num1, num2, num3, num4); // 16
    
    // 3. 布尔
    const bool: boolean = true;
    
    数组
    // 4. 数组(两种方式)
    const arr1: number[] = [1, 2]; // 数字类型数组
    // 范型数组定义形式
    const arr2: Array<string> = ['4', '5']; // 字符串数组
    console.log(arr1, arr2);
    
    元组
    // 5. turple元组,已知类型、顺序和数量确定的(可以定义多种元素类型,但是要按类型顺序赋值),局限性比较大,不推荐使用,使用场景极少
    const tur1: [number, string, boolean] = [1, '2', false];
    // 使用对应的元素,会自动推断出该元素类型的方法
    console.log(tur1[2].valueOf());
    
    枚举
    // 6. 枚举
    enum Sex {
      male,
      female,
    }
    const male: number = Sex.male;
    const female:number = Sex.female;
    console.log(male, female) // 下标索引
    // 手动赋值方式
    enum Color {
      red = 2,
      green = 'green',
    }
    const red: number = Color.red;
    const green: string = Color.green;
    console.log(red, green); // 2 'green'
    
    any
    // 7. any类型, 不声明变量类型,默认是any,常用场景:比如我们只知道一部分数据类型时,可以使用,但是尽量少用
    let any1: any;
    any1 = 7;
    any1 = false;
    let any2: any[];
    any2 = [1, false, 'xm'];
    
    // 8. void类型(空类型),使用场景:一般用于函数的返回值声明
    function void1(): void {
      console.log('void类型');
    }
    void1();
    
    null 和 undefined
    // 9. null和undefined, 所有类型的子类型,可以赋值给任意类型(但是这里实践会报错),使用场景: 对变量是否有值不确定时
    // 使用联合判断
    const null1: object | null = null;
    const undefined1: number | undefined = 12;
    console.log(null1, undefined1); // null 12
    
    Never
    // 10. never:永远不会有值的类型,是任意类型的子类型,但是它没有自己的子类型。使用场景:抛出异常的函数,很少使用,一般使用void进行处理
    function never1(msg: string): never {
      throw new Error(msg);
    }
    // never1('never实践 ');
    
    function never2(): never {
      while(true) {
        console.log('never2');
      }
    }
    // never2();
    
    object
    // 11. object类型,非原始类型,除string、number、boolean、symbol之外的类型
    const obj1: object = { age: 18, name: 'xm' };
    const obj2: object = [1, 2];
    console.log(obj1, obj2);
    
    function obj3(o: object) {
      console.log(o);
    }
    obj3({ a: 1 });
    obj3([1, 2]);
    
    类型断言
    // 12. 类型断言,修改已知的变量类型为自定义的变量类型(没有运行时的影响,只会在编译阶段起作用)
    
    // 方式1
    const asset1: any = 'i like, like i';
    const asset2: string = (<string>asset1).substring(0, 3);
    const asset3: any = 456;
    const asset4: string = (<number>asset3).toFixed(4);
    console.log(asset2, asset3);
    
    // 方式2
    const asset5: any = false;
    const asset6: boolean = (asset5 as boolean).valueOf();
    console.log(asset6)
    

    03.函数的参数

    基本函数参数
    // 基本函数参数
    function fun2(params: string): void {
      console.log(params);
    }
    fun2('基本函数参数');
    
    可选参数的函数,必选参数不能放在可选参数后
    // 可选参数的函数,必选参数不能放在可选参数后
    function fun3(params1: boolean, params2?:number) { // 函数不显式指定返回类型时,默认为void类型
      console.log(params1, params2);
    }
    fun3(false); // false, undefined
    fun3(true, 13); // true, 13
    
    默认参数的函数
    // 默认参数的函数
    function fun4(params:string[] = ['str']) {
      console.log(params);
    }
    fun4(); // ['str']
    fun4(['test']); // ['test']
    
    剩余参数的函数
    // 剩余参数的函数
    function fun5(...args: any[]): string {
      return args.reduce((prev, curr) => {
        return prev += (curr + '、');
      }, '');
    }
    const res: string = fun5('cs', 27, 175, '65kg', false);
    console.log(res);
    

    04.接口

    作用:在开发中,为类命名和为项目中的代码或者第三方代码库定义规范

    接口属性必填
    // 1. 定义接口
    interface Person {
      name: string,
      job: string,
      age: number,
    }
    
    // 规范化变量
    const person: Person = {
      name: 'xm',
      age: 18,
      job: 'it',
    }
    
    // 规范化函数参数
    function outPerson(person: Person) {
      console.log(person.name);
    }
    outPerson(person);
    
    接口中可选属性
    // 2. 接口中可选属性
    interface CircleParam {
      color?: string,
      radius?: number,
    }
    
    interface CircleRes {
      color: string,
      area: number,
    }
    
    function createCircle(circle:CircleParam): CircleRes {
      const defaultCircle = { color: 'red', area: 100 };
      if (circle.color) {
        defaultCircle.color = circle.color;
      }
      if (circle.radius) {
        defaultCircle.area = Math.PI * Math.pow(circle.radius, 2);
      }
      return defaultCircle;
    }
    
    const createCircle1 = createCircle({color: 'blue'});
    const createCircle2 = createCircle({radius: 12});
    const createCircle3 = createCircle({color: 'green', radius: 14});
    console.log(createCircle1, createCircle2, createCircle3);
    
    接口只读属性
     // 3. 接口的只读属性
    interface FullName {
      readonly firstName: string,
      readonly lastName: string,
    }
    const fullName: FullName = {
      firstName: 'c',
      lastName: 'xm',
    }
    fullName.lastName = 'ss'; // warning: read-only
    console.log(fullName) // 虽然可以编译痛殴,但是ts已经报了警告
    
    // 只读数组
    const colors: ReadonlyArray<number> = [1, 2, 3];
    colors.push(5); // 直接警告colors read-only
    console.log(colors);
    
    接口的任意定义属性
    interface SquareConfig {
      width: number,
      height: number,
      [propName: string]: any, // 自定义属性名称
    }
    
    function area(params: SquareConfig): void {
      const areaVal = params.width * params.height;
      console.log(areaVal, params);
    }
    area({ width: 20, height: 10, desc: '矩形', title: '矩形title' });
    

    05.定义函数类型

    // 最简洁方式
    interface Func1 {
      (param1: number, param2: number): boolean, // 定义接口函数
    }
    
    // 对箭头函数进行接口约束,适用于模块化开发
    const func1Test: Func1 = (a, b) => {
      console.log(a > b);
      return a > b;
    }
    
    func1Test(4, 1);
    

    06.索引类型

    // 可索引类型
    interface IndexType {
      [index: number]: string, // 自定义字符串类型的索引数组,适用于模块化开发
    }
    const indexArr: IndexType = ['xm', '2'];
    const indexStr: string = indexArr[0];
    console.log(indexStr);
    

    07.类类型

    // 类类型
    // 接口中声明属性和方法(只会检查类的公共属性和方法, 私有和受保护类型不会检查)
    interface ClockInterface {
      currDate: Date,
      setDate(d: Date): void,
    }
    // 对类通过接口进行规范
    class Clock implements ClockInterface {
      currDate: Date; // 声明接口中的属性,方法不用重新声明
      constructor(currDate: Date) {
        this.currDate = currDate;
        console.log(this.currDate);
      }
      setDate(d: Date) {
        console.log(d);
      }
    }
    
    const clock = new Clock(new Date());
    clock.setDate(new Date());
    

    08.接口继承

    接口继承(一个接口的成员复制到另一个接口)

    分割重用的思想

    // 继承单接口
    interface People {
      firstName: string,
    }
    
    // 接口继承,并且继承firstName属性
    interface Programmer extends People {
      job: string,
    }
    
    // 使用断言的方式,定义属性规范
    const programmer = {} as Programmer;
    
    programmer.firstName = 'wang';
    programmer.job = 'web';
    console.log(programmer);
    
    // 继承多接口
    interface Male {
      sex: string,
    }
    // 多接口继承,用','分开
    interface Student extends Male, People {
      class: string,
    }
    
    const student = {} as Student;
    student.firstName = 'li';
    student.sex = '男';
    student.class = '三年级';
    console.log(student);
    

    09.类与继承

    class Animal {
      name: string;
      constructor(props: { name: string }) {
        this.name = props.name;
      }
      sayAnimal() {
        console.log('sayAnimal' + this.name);
      }
    }
    
    class Cat extends Animal {
      kind: string;
      constructor(props: { name: string, kind: string }) {
        super(props);
        this.kind = props.kind;
      }
      sayCat() {
        console.log(`我是${this.name},属于${this.kind}`);
      }
    }
    
    const cat = new Cat({ name: '小黑', kind: '猫' });
    cat.sayAnimal();
    cat.sayCat();
    

    10.子类重写并在内部调用父类方法

    内部通过super调用父类的方法

    class Mammal {
      name: string;
      constructor(name: string) {
        this.name = name;
      }
      move(distance: number = 0) {
        console.log(`${this.name}跑了${distance}m`);
      }
    }
    
    class Horse extends Mammal {
      constructor(name: string) {
        super(name);
      }
      move() {  // 重写父类方法
        console.log('开始调用父类的方法');
        // 内部通过super调用父类的方法
        super.move(200);
      }
    }
    
    const horse = new Horse('小马');
    horse.move();
    

    11.类类型说明与比较

    公共类型

    公共类型作用域在当前类、当前类实例和其子类以及子类实例中

    // 当前类
    class People {
      // 不声明默认就是public类型
      name: string;
      public age: number; // 公共类型
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
      peopleSay() {
        console.log(this.name, this.age);
      }
    }
    
    // 子类
    class Man extends People {
      constructor() {
        super('xm', 18);
      }
      manSay() {
        // 公共属性可以访问到
        console.log(this.name, this.age);
      }
    }
    
    const people = new People('people', 24);
    const man = new Man();
    // 公共属性外层实例可以访问到
    people.peopleSay();
    console.log('people.name', people.name);
    man.manSay();
    console.log('man.name', man.name);
    
    受保护类型

    受保护类型作用域仅在当前类中和其子类中

    // 受保护类型
    class Car {
      protected price: number;
      constructor(price: number) {
        this.price = price;
      }
      carSay() {
        console.log('car say', this.price);
      }
    }
    
    class Auto extends Car {
      constructor() {
        super(2000);
      }
      autoSay() {
        console.log('auto say', this.price);
      }
    }
    
    const car = new Car(30000);
    car.carSay();
    console.log(car.price);
    const auto = new Auto();
    auto.autoSay();
    console.log(auto.price);
    
    私有类型

    私有类型作用域仅在当前类中

    // 私有类型
    class Job {
      private place: string;
      constructor(place: string) {
        this.place = place;
      }
      jobSay() {
        console.log('job place', this.place);
      }
    }
    
    class Teacher extends Job {
      constructor() {
        super('学校');
      }
      teacherSay() {
        console.log('teacher place', this.place); //  属性“place”为私有属性,只能在类“Job”中访问。
      }
    }
    
    const teacher = new Teacher();
    console.log(teacher.place); // 属性“place”为私有属性,只能在类“Job”中访问。// 私有类型
    class Job {
      private place: string;
      constructor(place: string) {
        this.place = place;
      }
      jobSay() {
        console.log('job place', this.place);
      }
    }
    
    class Teacher extends Job {
      constructor() {
        super('学校');
      }
      teacherSay() {
        console.log('teacher place', this.place); //  属性“place”为私有属性,只能在类“Job”中访问。
      }
    }
    const job = new Job('工厂');
    job.jobSay();
    console.log('jon 实例', job.place); // 属性“place”为私有属性,只能在类“Job”中访问。
    const teacher = new Teacher();
    console.log(teacher.place); // 属性“place”为私有属性,只能在类“Job”中访问。
    
    类修饰符

    readonly 只能在声明时或者构造函数中被初始化,作用域为当前类、当前类实例和其子类以及子类实例中都可访问,但不能修改

    // readonly 
    class DecoratorClass {
      readonly name: string = 'readonly';
      updateProp() {
        this.name = 'update readonly'; // Cannot assign to 'name' because it is a read-only 
      }
    }
    class SubDecoratorClass extends DecoratorClass {
      constructor() {
        super();
      }
      subUpdateProp() {
        console.log('sub', this.name);
      }
    }
    const decoratorClass = new DecoratorClass();
    console.log(decoratorClass.name);
    const subDecoratorClass = new SubDecoratorClass();
    subDecoratorClass.subUpdateProp();
    

    12.类的静态属性

    静态属性只属于当前类的属性,不属于类实例的属性

    // static
    class StaticClass {
      static fullName: string = 'xm';
      age: number = 18;
      desc() {
        // 静态属性只能通过StaticClass去访问,不属于实例对象this的属性
        console.log(StaticClass.fullName + '芳龄' + this.age);
      }
    }
    
    const staticClass = new StaticClass();
    staticClass.desc();
    

    13.抽象类

    • 抽象类是派生类的基类,直观理解:抽象类是父类,派生类是子类。抽象类中也可以定义抽象方法,只需定义签名方法就可以,具体实现可以放在派生类中实现
    • 派生类只能继承抽象方法、公共方法与属性,不能继承基类的抽象属性
    • 抽象类不能进行实例化,一般使用场景很少,只做了解
    // 抽象类
    abstract class Department {
      go() {
        console.log('开始go');
      }
      abstract say(): void; // 不能有具体实现,必须定义在抽象类中
    }
    
    class Hr extends Department {
      
      say() { // 对抽象方法具体实现
        console.log('我是派生类的具体实现');
      }
    }
    
    const hr = new Hr();
    hr.go();
    hr.say();
    

    14.泛型

    基础使用

    可灵活定义数据类型,用封装的思想将数据类型统一规范化

    // 泛型基本使用,对输入输出类型统一化
    // 基本格式
    function print<T>(param: T): T {
      return param;
    }
    
    console.log(print('xm'));
    console.log(print(true));
    console.log(print(10));
    
    // 泛型基本使用,对输入输出类型统一
    function print<T>(param: T[]): T[] {
      console.log(param.length);
      return param;
    }
    
    // 使用泛型定义数组,比元组更好用的方式,数组中元素可以是任意类型
    console.log(print(['xm', false, 10, [1, 2]]));
    
    强制规范泛型的属性

    强制传入的参数中含有某个属性

    // 例如传入参数中必须包含length属性
    interface LengthProp {
      length: number;
    }
    class Len<T extends LengthProp> {
      name: T;
      constructor(name: T) {
        console.log(name.length);
        this.name = name;
      }
    }
    
    const len1 = new Len('100'); // 3
    const len2 = new Len(100); // undefined, error: 数值100不含有length属性
    const len3 = new Len({ a: 1, length: 999 }); // 999
    
    // 传入对象中必须包含某个key, 使用keyof关键字进行判断,可作为进阶用法了解
    class ObjKey<T, K extends keyof T> {
      constructor(obj: T, key: K) {
        console.log(obj[key]);
      }
    }
    
    const objKey1 = new ObjKey({a: 1}, 'a');
    const objKey2 = new ObjKey({a: 1}, 'c'); // error: c不是{a: 1}中的属性
    

    15.类型推断(比较简单,不做详细记录)

    类型推断默认使用最佳通用规则自动推断,如果我们对类型加上注解之后,就会以我们添加的类型注解进行推断

    // 类型自动推断
    let hobby = 'ball'; // string
    hobby = 10; // 不能将类型“number”分配给类型“string”
    
    const props = ['xm', 10, null, undefined, false]; // (string | number | boolean | null | undefined)[]
    

    相关文章

      网友评论

          本文标题:TypeScript记录

          本文链接:https://www.haomeiwen.com/subject/dasxphtx.html