• ts学习笔记


    目录

    ts介绍及安装

    ts介绍及安装

    • Typescript是由微软开发的开源,跨平台的编程语言。- 它是javascript的超集,主要提供了类型系统对ES6+的支持,最终也会被编译成javascript。
    • 它主要为大型应用的开发设计的,并且最终会编译成javascript。
    • 它对javascript语法进行了扩展,所有原来的JavaScript程序都可以运行在typescript的环境中。

    ts的特点:

    • 始于javascript,又归于js
    • 强大的类型系统
    • 先进的javascript:TypeScript 提供最新的和不断发展的 JavaScript 特性

    安装ts命令:

    npm install typescript -g
    
    • 1

    检查ts是否安装成功命令(查看ts版本):

    tsc -v
    
    • 1

    手动编译ts

    手动编译ts

    // 01.第一个ts.ts
    (() => {
        function sayHi(str: string) {
            return `hello ${str}`;
        }
        let str = 'lily';
        console.log(sayHi(str));
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该文件需要通过tsc 01.第一个ts.ts命令编译成对应的01.第一个ts.js文件,然后可以在index.html文件中引入查看执行结果。

    // index.html
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Documenttitle>
    head>
    <body>
        <script src="./01.第一次的ts.js">script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意:

    • 直接在html文件中引入ts代码会报错,需要使用tsc ts文件名命令编译ts为js,然后引入编译后的js文件。
    • ts文件中的函数中的形参如果使用了某个类型进行修饰,那么最终在编译的js文件中是没有这个类型的。
    • 在ts中使用let声明变量,但是编译成js后会用var来声明变量。

    vscode自动编译ts

    vscode自动编译ts

    • 首先在vscode的终端中执行tsc --init命令,此时会生成一个tsconfig.json文件
    • 打开该文件可以修改其中的配置,比如
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    "outDir": "./js",                                   /* 最终编译的js文件自动放到js文件夹中 */
    
    // "strict": true,                                      /* Enable all strict type-checking options. */
    "strict": false,                                      /* 不使用严格模式 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 启动vscode中的监视任务:终端–》运行任务–》显示所有任务–》tsc:监视-*******/config.json

    通过上述操作就能在vscode中自动将ts文件编译成js文件。

    类型注解

    类型注解

    TypeScript 里的类型注解是一种轻量级的为函数或变量添加约束的方式。TypeScript提供了静态的代码分析,它可以分析代码结构和提供的类型注解。

    (() => {
        function showMsg(str: string) {
            return `hello ${str}`;
        }
        let msg = [1, 2, 3];
        // let msg = 'lily';
        console.log(showMsg(msg));
    })();
    // 此时将函数 参数msg变为数组时编译ts文件会报错,但是依然编译成了js文件,但是可能会出现一些无法预期的错误
    01_Typescript/02.ts在vscode中自动编译/01.类型注解.ts:8:25 - error TS2345: Argument of type 'number[]' is not assignable to 
    parameter of type 'string'.
    
    8     console.log(showMsg(msg));
                              ~~~
    
    [上午9:37:41] Found 1 error. Watching for file changes.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ts中的类

    ts中的类

    // 下面这个例子只是将上面例子中的函数参数由对象换成了类的实例
    (() => {
        interface IPerson {
            firstName: string,
            lastName: string,
        };
        class Person {
            firstName: string;
            lastName: string;
            fullName: string;
            constructor(firstName: string, lastName: string) {
                this.firstName = firstName;
                this.lastName = lastName;
                this.fullName = `${firstName} ${lastName}`;
            }
        }
        function showFullName (person: IPerson) {
            return `${person.firstName}_${person.lastName}`;
        }
        let person = new Person('欧阳', '夏丹');
        console.log(showFullName(person));
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    webpack打包ts

    webpack打包ts

    1. 在指定的文件夹下执行npm init -y命令来初始化当前文件夹下的package.json文件。
    2. 下载相关依赖:
      • npm install --save typescript
      • npm install --save webpack@4.41.5 webpack-cli@3.3.10 webpack-dev-server@3.10.2
      • npm install --save html-webpack-plugin@4.4.1 clean-webpack-plugin
      • npm install --save ts-loader@4.0.0 cross-env
    3. 创建入口文件src/main.js
    4. 创建打包后的html模板public/index.html
    5. 配置build/webpack.config.js文件
    // clean-webpack-plugin这个插件会在打包前删除原来打包的文件
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    // html-webpack-plugin这个插件会帮助我们在 webpack 打包结束后,自动生成一个 html 文件,并把打包产生文件引入到这个 html 文件中去。
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    const isProd = process.env.NODE_ENV === 'production' // 是否生产环境
    
    function resolve (dir) {
      return path.resolve(__dirname, '..', dir)
    }
    
    module.exports = {
      mode: isProd ? 'production' : 'development',
      entry: {
        app: './src/main.ts'
      },
    
      output: {
        path: resolve('dist'),
        filename: '[name].[contenthash:8].js'
      },
    
      module: {
        rules: [
          {
            test: /\.tsx?$/,
            use: 'ts-loader',
            include: [resolve('src')]
          }
        ]
      },
    
      plugins: [
        new CleanWebpackPlugin({
        }),
    
        new HtmlWebpackPlugin({
          template: './public/index.html' // 指定以这个目录下的html文件为模板
        })
      ],
    
      resolve: {
        extensions: ['.ts', '.tsx', '.js']
      },
    
      devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',
    
      devServer: {
        host: 'localhost', // 主机名
        stats: 'errors-only', // 打包日志输出输出错误信息
        port: 8081,
        open: true
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    1. 配置webpack打包命令在package.json文件中
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
    
    • 1
    • 2

    基础类型

    基础类型

    (() => {
        // 布尔类型
        let flag: boolean;
        flag = true;
        console.log(flag);
    
        // 数字类型
        let n1: number = 1; // 十进制
        let n2: number = 0b01; // 以0b开头是二进制
        let n3: number = 0o12; // 以0o开头是八进制
        let n4: number = 0xa; // 以0x开头是十六进制
        console.log(n1, n2, n3, n4);
    
        // 字符串类型
        let str1: string = '床前明月光';
        let str2: string = '疑是地上霜';
        console.log(`${str1},${str2}`);
    
        // 字符串和数字的拼接
        let num: number = 10;
        let str: string = '这个数字是';
        console.log(str + num); // 这个数字是10
        let ss: string = str + num;
        console.log(ss); // 这个数字是10
    
        // null与undefined
        let nul: null = null;
        let udf: undefined = undefined;
        console.log(nul, udf);
        let num1: number = undefined;
        // 注意:null与undefined都可以作为其他类型的子类型,也就是可以把null和undefined赋值给其他类型的变量
        
        // 数组
        //  - 语法1:let 变量名: 成员项类型[] = [值1, 值2]
        let arr1: number[] = [1, 2, 3];
        //  - 语法2:let 变量名: Array<成员项类型> = [值1, 值2]
        let arr2: Array<number> = [1, 2, 3];
        console.log(arr1, arr2);
        // 注意:数组定义后,里面的数据类型必须和定义数组时的类型一致,否则有错误提示信息,也不能编译通过
        
        // 元组:它类似数组,但是里面允许成员项是不同的数据类型,但是类型的数目和位置和赋值时数据的数目和位置必须一致
        let arr3: [string, number, boolean] = ['lily', 10, true];
        // 注意:元组类型在使用时数据位置和个数应该和在定义元组时数据类型及位置一致
        
        // 枚举enum:当一组数据常用且个数固定此时可以定义成枚举类型,可以通过名字获取对应的值,使用枚举类型可以为一组数值赋予友好的名字
        // 枚举里面的每个数据都可以叫元素,每个元素都有自己的编号,编号从0开始,依次加1
        enum Color {
            red,
            green,
            blue,
        };
        let red: Color = Color.red;
        console.log(red, Color.red, Color.green, Color.blue); // 0 0 1 2
        enum Color1 {
            red = 1,
            green,
            blue,
        };
        console.log(Color1.red, Color1.green, Color1.blue); // 1 2 3
        enum Color2 {
            red = 1,
            green = 10,
            blue = 1000,
        };
        console.log(Color2.red, Color2.green, Color2.blue, Color2[1000]); // 1 10 1000 'blue'
        
        // any类型:表示任意数据类型,在不确定当前数据是什么类型时可以用any类型的变量将数据存储起来
        let str3: any = 100;
        str3 = 'lily';
        console.log(str3);
        // 当一个数组中的数据个数不确定,类型不确定可以定义成any类型的数组
        let arr4: any[] = ['lily', 100, true];
        // console.log(arr4[0].toFixed()); // 这也是用any类型的弊端,在编译时通过,但在实际执行时会报错,因为此处数字类型没有toFixed这个方法
        
        // void:表示没有任何数据类型,在函数声明时在小括号后面加上:void表示函数没有返回值
        function fn (): void {
            console.log('ceshi');
            // return;
            // return undefined;
            // return null;
        }
        console.log(fn());
        let vd: void = null; // 可以定义一个void类型的变量,用null或undefined对其进行赋值,因为null和undefined是任何数据类型的子类型
        
        // object类型
        function fn1(obj: object): object {
            console.log(obj);
            return {
                name: 'lily',
                age: 10,
            };
        }
        console.log(fn1({ name: 'lilei', age: 10 }));
        // console.log(fn1('111')); // 报错,因为要传入对象类型
        console.log(fn1(new String(1))); // String {'1'}
        console.log(fn1(String)); // String() { [native code] }
        
        // 联合类型:表示取值可以是多种类型中的一种
        // 需求:定义一个函数得到一个数字或字符串的字符串形式
        function fn2(str: number | string): string { // 该函数的形参可以是数字类型或字符串类型
            return str.toString();
        }
        console.log(fn2(123));
        console.log(fn2('hello'));
    
        // 类型断言
        //  - 语法1:<类型名称>变量名
        //  - 语法2:变量名 as 类型名称
        // 但是上面的需求实现中可以区分下是否是字符串,如果是字符串直接返回,如果不是字符串调用toString
        function fn3(str: number | string): string {
            if ((str as string).length) { // 如果存在length属性说明是字符串可以直接返回,此时需要用类型断言
                return str as string;
            }
            // if ((str).length) { // 如果存在length属性说明是字符串可以直接返回,此时需要用类型断言
            //     return str;
            // }
            return str.toString();
        }
        console.log(fn3(123));
        console.log(fn3('hello'));
    
        // 类型推断
        let num2 = 10;
        // num2 = '111'; // 此时ts的静态解析会报错,因为在初始化num2时由于赋值了number类型,所以经过类型推断该变量是number类型
        let param; // 此时param在变量初始化时没有赋值则经过类型推断它的类型是any,所以下面可以给它赋任何类型的值
        param = 10;
        param = '111';
    
        // 总结:ts中变量一开始是什么类型,那么后期赋值的时候,只能用这个类型的数据,是不允许用其他类型的数据赋值给当前的这个变量
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130

    注意:

    • null与undefined都可以作为其他类型的子类型,也就是可以把null和undefined赋值给其他类型的变量
    • ts中变量一开始是什么类型,那么后期赋值的时候,只能用这个类型的数据,是不允许用其他类型的数据赋值给当前的这个变量
    • 数组类型的语法
      • let 变量名: 成员项类型[] = [值1, 值2]
      • let 变量名: Array<成员项类型> = [值1, 值2]
    • 元组:它类似数组,但是里面允许成员项是不同的数据类型,但是类型的数目和位置和赋值时数据的数目和位置必须一致
    • 枚举类型:当一组数据常用且个数固定此时可以定义成枚举类型,使用枚举类型可以为一组数值赋予友好的名字,可以通过名字获取对应的值。枚举里面的每个数据都可以叫元素,每个元素都有自己的编号,编号从0开始,依次加1
    • any类型:表示任意数据类型,在不确定当前数据是什么类型时可以用any类型的变量将数据存储起来。当一个数组中的数据个数不确定,类型不确定可以定义成any类型的数组
    • void类型和any类型正好相反,表示没有任何类型

    接口

    接口

    接口定义使用interface关键字,接口是一种对象的属性或行为的抽象。示例如下

    (() => {
        // 定义接口
        interface IPerson {
            firstName: string,
            lastName: string,
        };
        // 限定函数参数类型,这样在函数中使用形参时会自动提示变量中的属性
        function showFullName (person: IPerson) {
            return `${person.firstName}_${person.lastName}`;
        }
        let person = {
            firstName: '欧阳',
            lastName: '夏丹',
        };
        // 在调用函数时如果传入的参数不含IPerson定义的结构的话ts编译会报错,但是代码执行时可能会出现未知错误
        console.log(showFullName(person));
        
        // 接口是一种对象的属性或行为的抽象
        // 需求:id是number类型, 必须有, 只读的
        //      name是string类型, 必须有
        //      sex是string类型, 可以没有
        interface IPerson {
            readonly id: number, // 用readonly表示id字段是只读的
            name: string,
            sex?: string, // 用?表示sex字段可以可无
        };
        let person: IPerson = {
            id: 1,
            name: 'lily',
            sex: 'female',
        };
        // person.id = 2; // 报错,id字段是只读的
        delete person.sex; // 不报错,sex字段可有可无
        console.log(person);
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    注意

    • 在定义接口时readonly表示字段是只读的
    • 在定义接口时?表示字段可有可无。可选属性的好处之一是可以对可能存在的属性进行预定义,好处之二是可以捕获引用了不存在的属性时的错误。

    接口定义函数类型

    接口定义函数类型

    为了用接口定义函数类型,需要在接口中定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

    interface IPersonInfo {
        (name: string, age: number): string,
    };
    let fn: IPersonInfo = (name: string, age: number): string => {
        return `${name} + ${age}`;
    };
    console.log(fn('lily', 10));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接口定义类类型

    接口定义类类型

    类可以通过implements实现一个接口或多个接口,或者说一个或多个接口可以同时约束一个类。

    interface sport {
        run(),
    };
    class Person implements sport {
        run() {
            console.log('我会跑');
        }
    }
    let p = new Person;
    p.run();
    interface hobby {
        myHobby(),
    };
    class Person1 implements sport, hobby {
        run() {
            console.log('我会跑');
        }
        myHobby() {
            console.log('我的爱好是听音乐');
        }
    }
    let p1 = new Person1;
    p1.myHobby();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    接口的继承

    接口的继承

    接口可以通过extends继承一个或多个接口。

    interface IPersonNew extends sport, hobby {
        food()
    };
    class Person2 implements IPersonNew {
        run() {
            console.log('我会跑');
        }
        myHobby() {
            console.log('我的爱好是听音乐');
        }
        food() {
            console.log('我爱吃的食物是香蕉');
        }
    }
    let p2 = new Person2;
    p2.food();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ts中的类

    ts中的类

    (() => {
        class Person {
            name: string
            age: number
            sex: string
            constructor(name: string = 'lily', age: number = 10, sex: string = '女') {
                this.name = name;
                this.age = age;
                this.sex = sex;
            }
            info(str: string): string {
                return `${str},我的名字是${this.name},年龄是${this.age},性别是${this.sex}`;
            }
        }
        let p = new Person;
        console.log(p.info('hello'));
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    类的继承

    类的继承

    继承是类与类之间的关系,通过extends关键字实现。最基本的继承:类从基类中继承了属性和方法。被继承的基类是父类也是超类,继承的类为子类,也称为派生类。

    class Animal {
        name: string
        constructor(name: string) {
            this.name = name;
        }
        run(distance: number) {
            console.log(`${this.name}跑了${distance}`);
        }
    }
    class Horse extends Animal {
        constructor(name: string) {
            super(name);
        }
        run(distance: number = 5) {
            console.log('我是horse中的run');
            super.run(distance); //这是调用父类的run方法 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:

    • 子类可以重写父类中的方法
    • 子类中通过使用super关键字调用父类的构造函数,并且可通过super方法调用父类中的方法

    类的多态

    类的多态

    类的多态就是父类型的引用指向子类型的对象,不同类型的对象针对相同的方法产生不同的行为。

    class Animal {
        name: string
        constructor(name: string) {
            this.name = name;
        }
        run(distance: number = 0) {
            console.log(`${this.name}跑了${distance}`);
        }
    }
    class Horse extends Animal {
        constructor(name: string) {
            super(name);
        }
        run(distance: number = 5) {
            console.log(`我是${this.name}中的run`);
        }
    }
    class Dog extends Animal {
        constructor(name: string) {
            super(name);
        }
        run(distance: number = 10) {
            console.log(`我是${this.name}中的run`);
        }
    }
    // 父类型的引用指向不同的子类型对象
    let h: Animal = new Horse('hourse');
    let d: Animal = new Dog('dog');
    function showMsg(a: Animal) {
        a.run();
    }
    // 不同类型的对象的相同方法产生的行为不同
    showMsg(h);
    showMsg(d);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    类的成员修饰符

    类的成员修饰符

    类中的修饰符:用可访问性于描述类中成员(属性、构造函数、方法)的可访问性

    • public修饰符:类中成员默认都被public修饰,可以被类内部和外部及子类中使用
    • private修饰符:只能被类内部使用,类外部和子类中都不能使用
    • proteced修饰符:只能在父类和子类内部使用,不能在外部使用
    class Animal {
      public name: string
      public constructor (name: string) {
        this.name = name;
      }
      public run (distance: number = 0) {
        console.log(`${this.name} run ${distance}m`);
      }
    }
    class Person extends Animal {
      private age: number = 18
      protected sex: string = '男'
      run (distance: number = 5) {
        console.log('Person jumping...');
        super.run(distance);
      }
    }
    class Student extends Person {
      run (distance: number = 6) {
        console.log('Student jumping...');
        console.log(this.sex); // 子类能看到父类中受保护的成员
        // console.log(this.age); //  子类看不到父类中私有的成员
        super.run(distance);
      }
    }
    console.log(new Person('abc').name); // 公开的可见
    // console.log(new Person('abc').sex); // 受保护的不可见
    // console.log(new Person('abc').age); //  私有的不可见
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    readonly修饰符

    readonly修饰符

    类使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

    class Person {
        readonly name: string
        constructor(name: string) {
            this.name = name;
            this.name = 'sanhao'; // 在构造函数中是可以修改name属性的
        }
        sayHi() {
            // this.name = 'haha'; // 此处不能修改name属性,它是只读的
            console.log('你好,' + this.name);
        }
    }
    let p = new Person('lily');
    // p.name = 'lilei'; // 此处不能修改name属性,它是只读的
    console.log(p.name); // 'sanhao'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    class Person {
        // 在属性声明时直接赋值后还可以在构造函数中修改该属性值,但是在其他地方则不能修改该属性值
        readonly name: string = 'lilei'
        constructor(name: string) {
            this.name = name; // 在构造函数中是可以修改name属性的
        }
        sayHi() {
            // 类中的普通方法中不能修改readonly修饰的属性
            // this.name = 'haha'; // 此处不能修改name属性,它是只读的
            console.log('你好,' + this.name);
        }
    }
    let p = new Person('lily');
    // p.name = 'lilei'; // 此处不能修改name属性,它是只读的
    console.log(p.name); // 'lily'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    一旦constructor函数中的参数如果被readonly修饰后,则该参数就是参数属性,即类的属性成员并且是只读的

    class Person {
        // 一旦constructor函数中的参数如果被readonly修饰后,则该参数就是参数属性,即类的属性成员并且是只读的
        constructor(readonly name: string) {
            this.name = name; // 在构造函数中是可以修改name属性的
            this.name = 'sanhao';
        }
        sayHi() {
            // this.name = 'haha'; // 此处不能修改name属性,它是只读的
            console.log('你好,' + this.name);
        }
    }
    let p = new Person('lily');
    // p.name = 'lilei'; // 此处不能修改name属性,它是只读的
    console.log(p.name); // 'sanhao'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 在构造函数中的参数用public修饰时相当于给类新增公有属性成员,该属性可以在类内部和外部使用
    • 在构造函数中的参数用private修饰时相当于给类新增私有属性成员,该属性只能在类内部使用
    • 在构造函数中的参数用protectd修饰时相当于给类新增受保护属性成员,该属性可以在类内部和外部使用
    class Person {
        // 在构造函数中的参数用public修饰时相当于给类新增public属性成员
        constructor(public name: string) {
            this.name = name; // 在构造函数中是可以修改name属性的
            this.name = 'sanhao';
        }
        sayHi() {
            // this.name = 'haha'; // 此处不能修改name属性,它是只读的
            console.log('你好,' + this.name);
        }
    }
    let p = new Person('lily');
    // p.name = 'lilei'; // 此处不能修改name属性,它是只读的
    console.log(p.name);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    存取器

    存取器

    通过getter/setter来截取对对象成员的访问。用于控制对对象中成员项的访问。

    class Person {
        firstName: string
        lastName: string
        constructor(firstName: string, lastName: string) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        get fullName() {
            return `${this.firstName}_${this.lastName}`;
        }
        set fullName(val) {
            const names = val.split('_');
            this.firstName = names[0];
            this.lastName = names[1];
        }
    }
    let p = new Person('东方', '不败');
    console.log(p.fullName); // '东方_不败'
    p.fullName = '诸葛_孔明';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    注意: 如果只有get没有set,则fullName是只读属性

    静态属性

    静态属性

    静态成员:类中通过static修饰的属性或方法称为静态成员,静态成员在使用时通过类名.成员名的方式调用

    class Person {
        // 注意类中有一个默认的静态成员属性name
        static nameClass: string
        constructor() {}
        static sayHi() {
            console.log('hi');
        }
    }
    Person.nameClass = 'xiaotiantian';
    console.log(Person.nameClass);
    Person.sayHi();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意:类的构造函数constructor不能用static方法

    抽象类

    抽象类

    通过abstract修饰的类称为抽象类,不能被实例化。它里面可以用abstract修饰定义抽象方法,不能有实现;也可以定义实例方法。抽象类的子类必须实现抽象类中的抽象方法。

    // 抽象类用abstract修饰
    abstract class Animal {
        // 用abstract修饰的方法是抽象方法,没有实现
        abstract run()
        // 实例方法
        eat() {
            console.log('吃');
        }
    }
    // let a = new Animal; // 报错,抽象类不能被实例化
    class Dog extends Animal {
        run() {
            console.log('dog run');
        }
    }
    const d = new Dog;
    d.run();
    d.eat(); // 调用的是抽象类中的实例方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    函数

    函数

    ts中的函数和js中的函数一样,分为具名函数(函数声明),匿名函数(函数表达式)。只是多了类型限制。

    function add(x: number, y: number): number {
        return x + y;
    }
    let add1 = function(x: number, y: number): number {
        return x + y;
    }
    // 上面add1的完成形式可以写成下面的add2
    let add2: (x: number, y:number) => number = function(x: number, y: number): number {
        return x + y;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    默认参数和可选参数

    默认参数和可选参数

    函数中用? 修饰的参数是可选参数

    // 需求:定义一个函数,如果不传参数返回默认参数,如果只传姓氏返回姓氏,如果传姓氏和名字则返回姓氏名字
    // 这个函数中用? 修饰的参数是可选参数
    let getFullName = function(firstName: string = '东方', lastName?: string) {
        if (lastName) {
            return `${firstName}_${lastName}`;
        }
        return firstName;
    }
    console.log(getFullName()); // '东方'
    console.log(getFullName('诸葛')); // '诸葛'
    console.log(getFullName('诸葛', '孔明')); // '诸葛_孔明'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    剩余参数

    剩余参数

    注意:剩余参数必须放在函数定义时的最后面

    function add3 (x: string, ...args: string[]) {
        console.log(x);
        console.log(args);
    }
    add3('a', 'b', 'c'); // 'a' ['b', 'c']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    函数重载

    函数重载

    函数重载就是函数名相同,但是函数参数类型或个数不同。

    // 需求: 我们有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加
    // 函数的重载声明
    function add4(x: string, y: string): string
    function add4(x: number, y: number): number
    
    function add4(x: string | number, y: string | number): string | number {
        if (typeof x === 'string' && typeof y === 'string') {
            return x + y;
        }
        if (typeof x === 'number' && typeof y === 'number') {
            return x + y;
        }
    }
    console.log(add4(10, 10));
    console.log(add4('你好', '世界'));
    // console.log(add4(10, '世界')); // 报错,因为函数的重载声明中两个参数要么全部是string类型,要么是number类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    泛型

    泛型

    泛型就是在定义函数、接口、类是不确定数据类型,但在函数、接口、类使用时才能确定数据类型。使用其中尖括号中的大写字母随意。

    // 需求:根据指定的数量 count 和数据 value , 创建一个包含 count 个 value 的数组 
    // 下面这个是不用泛型的情况
    function getArr(value: any, count: number): any[] {
        let arr: any[] = [];
        for(let i = 0; i < count; i++) {
            arr.push(value);
        }
        return arr;
    }
    let arr = getArr(1, 3);
    console.log(arr[0].toFixed(2)); // '1.00' 此处在调用toFixed的时候没有智能提示
    console.log(getArr('hi', 3)); // ['hi', 'hi', 'hi']
    
    // 下面使用泛型的方式
    function getArr1<T>(value: T, count: number): T[] {
        // let arr: T[] = [];
        let arr: Array<T> = [];
        for(let i = 0; i < count; i++) {
            arr.push(value);
        }
        return arr;
    }
    let arr1 = getArr1<number>(2,3);
    console.log(arr1[0].toFixed(2)); // '2.00' 此处有智能提示
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    多个泛型参数的函数

    多个泛型参数的函数

    function getArr2<K, V>(value1: K, value2: V): [K, V] {
        return [value1, value2];
    }
    let arr2 = getArr2<string, number>('ha', 1);
    console.log(arr2); // ['ha', 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    泛型接口

    泛型接口

    class User {
       id: number
       name: string
       age: number
       constructor(id: number, name: string, age: number) {
           this.id = id;
           this.name = name;
           this.age = age;
       }
    }
    interface IPerson<T> {
       data: T[],
       add: (t: T) => void,
       get: (v: number) => T,
    }
    class Person implements IPerson<User>{
       data: User[] = [];
       add(v: User): void {
           this.data.push(v);
       }
       get(u: number): User {
           return this.data.find(item => item.id === u);
       }
    }
    let p: Person = new Person;
    p.add(new User(1, 'lily', 10));
    p.add(new User(2, 'lucy', 18));
    console.log(p);
    console.log(p.get(1));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    泛型类

    泛型类

    // 定义泛型类
    class Gener<T> {
       val: T
       add: (x: T, y: T) => T
    }
    // 在创建实例时指明类型
    let g = new Gener<number>;
    g.val = 10;
    g.add = function(x: number, y: number): number {
       return x + y;
    };
    console.log(g.add(1, 2));
    
    let gs = new Gener<string>;
    gs.val = 'hi';
    gs.add = function(x: string, y: string): string {
       return x + y;
    }
    console.log(gs.add('hi ', 'lily'));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    泛型约束

    泛型约束

    interface ILength {
       length: number,
    }
    function fn<T extends ILength>(x: T): number{
       return x.length;
    }
    console.log(fn('what?')); // 5
    // console.log(fn(11)); // 报错,因为函数参数是数字类型没有length属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    声明文件

    声明文件

    当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能

    /* 
    当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
    声明语句: 如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码
      declare var jQuery: (selector: string) => any;
    声明文件: 把声明语句放到一个单独的文件(jQuery.d.ts)中, ts会自动解析到项目中所有声明文件
    下载声明文件: npm install @types/jquery --save-dev
    */
    
    jQuery('#foo');
    // ERROR: Cannot find name 'jQuery'.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    一般声明文件都会单独写成一个 xxx.d.ts 文件。创建 01_jQuery.d.ts, 将声明语句定义其中, TS编译器会扫描并加载项目中所有的TS声明文件

    declare var jQuery: (selector: string) => any;
    
    • 1

    很多的第三方库都定义了对应的声明文件库, 库文件名一般为 @types/xxx, 可以在 https://www.npmjs.com/package/package 进行搜索

    有的第三库在下载时就会自动下载对应的声明文件库(比如: webpack),有的可能需要单独下载(比如jQuery/react)

    内置对象

    内置对象

    • ECMAScript中的内置对象:Number、Boolean、String、Date、RegExp、Array、Object、Function、Error
    /* 1. ECMAScript 的内置对象 */
    let b: Boolean = new Boolean(1)
    let n: Number = new Number(true)
    let s: String = new String('abc')
    let d: Date = new Date()
    let r: RegExp = /^1/
    let e: Error = new Error('error message')
    b = true
    // let bb: boolean = new Boolean(2)  // error
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • BOM和DOM中的内置对象:Window、Document、HTMLElement、DocumentFragment、Event、NodeList
    const div: HTMLElement = document.getElementById('test')
    const divs: NodeList = document.querySelectorAll('div')
    document.addEventListener('click', (event: MouseEvent) => {
      console.dir(event.target)
    })
    const fragment: DocumentFragment = document.createDocumentFragment()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    【Prism系列】Prism子窗口实现
    arm ubuntu 换源
    【教3妹学算法-每日3题(3)】最低加油次数
    STM32+UART串口+DMA收发
    拖死项目的不是团队,可能是失败的管理
    编程高手必学的内存知识05:深入理解页中断
    【B3637 最长上升子序列】
    植物大战僵尸机枪射手怎么发出多枚子弹
    深度学习--通过对Keras进行微调提升性能
    Leetcode (OK)242 1 219 (思路)383 202 (*)205 290 49
  • 原文地址:https://blog.csdn.net/u010510187/article/details/126246928