乐趣区

关于前端:ts学习总结

一、简介

TypeScript 是微软开发的一个开源的编程语言,通过在 JavaScript 的根底上增加动态类型定义构建而成。TypeScript 通过 TypeScript 编译器或 Babel 转译为 JavaScript 代码,可运行在任何浏览器,任何操作系统。

装置 ts

// 装置:npm install -g typescript

// 查看版本
tsc -v

注:编写 ts 文件,运行 ts 文件是先编译成 js 后在执行 js,想间接执行 ts,可装置 ts-node。

二、根底类型

js 根底类型分为两种:原始类型和对象类型,其中原始类型包含:数值、字符串、布尔值、null、undefined 以及 es6 中的 symbol、biignt。
ts 反对与 js 简直雷同的数据类型。

1、布尔值 / 字符串 / 数值

//var [变量名] : [类型] = 值;
let isDone: boolean = false;
const num: number = 1;
const name: string = "猪猪";

// 字符串模板仍旧能用
const str:string=`${name}`

// 申明变量的类型,但没有初始值,变量值会设置为 undefined://var [变量名] : [类型];
var test: string;

// 申明变量并初始值,但不设置类型,该变量能够是任意类型://var [变量名] = 值;
var uname = "abc";

// 申明变量没有设置类型和初始值,类型能够是任意类型,默认初始值为 undefined://var [变量名];
var cord;

(1)num 申明变量的类型 number 之后,前面赋值时,得跟数值,否则则会报错,因为变了 num 的类型是数值。

(2)如果变量的申明和赋值是同时进行的,ts 能够主动对变量进行类型检测。

let str: string;
str = 'hello';
str = 9; // 报错

2、null 和 undefined

// 这两个类型只有 本人
const onlyNull: null = null;
const onlyUndefined: undefined = undefined;

3、数组

// 数组泛型,Array< 元素类型 >
let list: Array<number> = [1, 2, 3];

//string[] 字符串数组
let list: string[];
list = ['a', 'b', 'c'];

//number[] 数值数组
let list: number[] = [1, 2, 3];

4、元组

元组 元组就是固定长度的数组

// 语法:[类型, 类型, 类型]
let list: [string, number];
list = ['hello', 123];

list = ['hello'];// 报错
list = [123, 'hello']; // 程序不统一
list = ['hello', 123, 11]; // 多余

5、枚举

枚举类型也的确属于对象类型
ts 只反对基于数字和字符串的枚举
对于基于数字的枚举类型反对键值对的反向映射 key<=>value
基于字符串的不能够反向映射?当然不能够, 就是纯 js 对象

//
// 枚举
enum Gender{
    Male,
    Female
}

let i: {name: string, gender: Gender.Male};
i = {
    name: '猴子',
    gender: Gender.Male
}

console.log(i.gender === Gender.Male); //true

字符串枚举

enum Language{
    java="J",
    node="N",
    php="P",
    python="PY"
  }
  
// 打印一下
console.log(Language)
// 输入后果
{java: 'J', node: 'N', php: 'P', python: 'PY'}

// 编译后的 js
var Language;
(function (Language) {Language["java"] = "J";
    Language["node"] = "N";
    Language["php"] = "P";
    Language["python"] = "PY";
})(Language || (Language = {}));
// 打印一下
console.log(Language);

  

数字枚举 - 默认增长

enum Language{
    html,
    node,
    js,
    python
  }
  
// 打印一下
console.log(Language)
  
// 输入后果
{
  '0': 'html',
  '1': 'node',
  '2': 'js',
  '3': 'python',
  html: 0,
  node: 1,
  js: 2,
  python: 3
}

// 编译后的 js
var Language;
(function (Language) {Language[Language["html"] = 0] = "html";
    Language[Language["node"] = 1] = "node";
    Language[Language["js"] = 2] = "js";
    Language[Language["python"] = 3] = "python";
})(Language || (Language = {}));
// 打印一下
console.log(Language);

数字枚举 - 自定义增长

enum Language{
    html=6,
    node,
    js,
    python
  }
  
// 打印一下
console.log(Language)

// 输入后果
{
  '6': 'html',
  '7': 'node',
  '8': 'js',
  '9': 'python',
  html: 6,
  node: 7,
  js: 8,
  python: 9
}

// 编译后的 js

var Language;
(function (Language) {Language[Language["html"] = 6] = "html";
    Language[Language["node"] = 7] = "node";
    Language[Language["js"] = 8] = "js";
    Language[Language["python"] = 9] = "python";
})(Language || (Language = {}));
// 打印一下
console.log(Language);

异构枚举

enum Person{
    age = 18,
    gender = 'male'
}
  
// 打印一下
console.log(Person)

// 输入后果
{'18': 'age', age: 18, gender: 'male'}

// 编译后的 js
var Person;
(function (Person) {Person[Person["age"] = 18] = "age";
    Person["gender"] = "male";
})(Person || (Person = {}));
// 打印一下
console.log(Person);

6、| 和 &

// | 或 示意能够是字符串或数值
let str: string | number;

str = 1;
console.log(str.length)// 报错
str = 'hello';
console.log(str.length)// 失常运行
str = false; // 报错

//& 示意同时
let str2: {name: string} & {age: number};
str2 = {name: '嘿嘿'}; // 报错
str2 = {name: '嘿嘿', age: 18};

7、type

// type
// 类型的别名
type myType = string;
let k: 1 | 2 | 3 | 4;
let m: myType //m 类型是 string

type myType2 =  1 | 2 | 3 | 4;
k = 1;
k = 6;// 报错

8、function

//js 不思考参数的类型和个数的
function sum(a, b) {return a + b;};

// ts 隐式 any
function sum(a: any, b:any):any {return a + b;};

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

let s1 = sum('1', 2); // 12
let s2 = sum(2, 2); // 4
let s3 = sum2(1, 5); // 6

console.log(s1, s2, s3);


9、任意值

任意值 (any/unknown) 用来示意容许赋值为任意类型

any

//any 示意任意类型的值,一个类型应用了 any 后相当于敞开了 ts 的类型检测
// 在应用 ts 时 不倡议应用 any

let a: any

a = 1;
a = 'hello';
a = false;

// 如果变量不申明类型,则 ts 解析器会主动判断变量的类型为 any(隐式 any)let b;

b = 1;
b = 'hello';
b = true;

let s: string;

// b 的变量是 any,它能够赋值给任意变量
s = b;

unknown

//unknown 示意未知类型的值

let c: unknown

c = 1;
c = 'hello';
c = false;

let s: string;

c = 'world';
// 把 c 赋值给 s,也就是把未知变量赋值给其余类型变量会报错
s = c;// 报错

//unknown 实际上就是一个类型平安的 any
//unknown 不能间接赋值给任意变量

// 判断类型
if (typeof c === 'string') {s = c;}

// 类型断言 用来通知解析器变量的理论类型
s = c as string;
s = <string> c;

10、void

const u:void=undefined;
const n:void=null;
const age:void=18;// 不能将 number 类型赋值给 void

//void 用来示意空 以函数为例 就示意没有返回值的函数
function fn() {}
function fn2(): void {}

11、never

//never 示意永远不会返回后果
function fn(): never {throw new Error('谬误的');
}

// 非凡状况下, 变量也能够应用 never 申明, 比方一个永远为空的数组。never 是任何类型的子类型, 也能够赋值给任何类型, 然而反过来不能够。(本身除外)
const emptyArr: never[] = []

12、object

//object 示意一个 js 对象
let a: object;
a = {}
a = function() {}

//{}用来指定对象中能够蕴含哪些属性
// 语法:{属性名:属性值}
// 属性名前面加上? 示意属性是可选的
let b: {name: string, age?: number};

b = {};// 报错 短少属性名

b = {name: '阿三'};
b = {name: '李四', age: 12};

// [propName: string]: any 示意任意类型的属性
let c: {name: string, [propName: string]: any};
c = {name: '嘿嘿', age: 12, gender: '男'};

// 设置函数构造的类型申明
// 语法:(形参:类型, 形参:类型...) => 返回值
let d: (a: number, b: number) => number;
d = function(n1, n2):number {return n1 + n2;}

//d = function(n1: string, n2:string): number {
//     return 10;
// }
// 报错

13、symbol

symbol 应用依赖 es6 编译辅助库 ,tsconfig.json lib[“es6”]

const sym1: symbol = Symbol();
const sym2: symbol = Symbol();
console.log(sym1===sym2); //false

let sym3 = Symbol("key");
let sym4 = Symbol("key");

sym2 === sym3; // false, symbol 是惟一的

三、面向对象

1⃣️操作浏览器应用 window 对象
2⃣️操作网页应用 document 对象
3⃣️操作控制台应用 console 对象

万物皆对象

1、类(class)

简介:要创建对象,必须先定义类,所谓的类能够了解为对象的模型。举例说明:能够通过 Person 类来创立人类的对象,通过 Dog 类来创立狗的对象等等,不同的类用来创立不同的对象。

Person 类

// 应用 class 关键字定义一个类

/**
 * 对象中蕴含了两个局部:*      属性
 *      办法
 * 
 */
class Person {
    // 定义实例属性
    name: string = '猴子';
    age: number = 18;
    // 动态属性
    static num: number = 1;
    // readonly
    readonly gender: string = '男';
    static readonly say: string = 'hello';
    
    // 定义方法
    /**
     * 
     * 通过 static 定义类办法 能够间接用类去调用
    */
    syaHello() {console.log('hello, 大家好');
    }
}
const son = new Person();
son.syaHello(); // hello, 大家好

console.log(son);
console.log(son.age, son.name);

console.log(son.age, son.name, son.num); // 报错 没有 num 这个属性

son.gender = '女'; // 报错 因为 readonly 是只读的属性 不可批改
Person.say = '1212'; // 应用 static 结尾且只读的属性 不可批改
Person.num; // 应用 static 结尾的属性是动态属性(类属性),能够间接通过类去调用


// 打印后果
Person {name: "猴子", age: 18}
18 "猴子"

dog 类

class Dog{
    name: string;
    age: number;

    // constructor 构造函数 构造函数会在对象创立时调用
    constructor(name: string, age: number) {
        // 在实例办法中 this 示意以后的实例
        // 能够通过 this 向新建的对象中增加属性
        this.name = name;
        this.age = age;
    }

    brak() {
        // 在办法中能够用 this 示意以后调用办法的对象
        //console.log('汪汪汪');
        console.log(this.name);
    }
}

const dog1 = new Dog('小黑', 10);
const dog2 = new Dog('小白', 11);

console.log(dog1); // {name: "小黑", age: 10}
console.log(dog2); // {name: "小白", age: 11}

dog1.brak(); // 小黑

2、继承

(function() {

    // 定义 animal 类
    class Animal {
        name: string;
        age: number;

        // constructor 构造函数 构造函数会在对象创立时调用
        constructor(name: string, age: number) {
            // 在实例办法中 this 示意以后的实例
            // 能够通过 this 向新建的对象中增加属性
            this.name = name;
            this.age = age;
        }

        sayHello() {console.log('动物在叫~');
        }
    }

    /**
     * 此时 Animal 被称为为父类 Dog、Cat 被称为子类
     * 应用继承后 子类将会领有父类的所有办法和属性
     * 如果在子类中增加了和父类的雷同的办法 则子类办法会笼罩父类的办法
    */
    // 定义狗的类 继承 Animal 类
    class Dog extends Animal {run() {console.log(`${this.name}在跑路~~~`);
        }
        sayHello() {console.log('汪汪汪');
        }
    }

    // 定义猫的类 继承 Animal 类
    class Cat extends Animal { }

    const dog = new Dog('小黑', 3);
    const cat = new Dog('咪咪', 2);

    console.log(dog); // Dog {name: "小黑", age: 3}
    dog.sayHello(); // 汪汪汪
    dog.run(); // 小黑在跑路~~~

    console.log(cat); //Dog {name: "咪咪", age: 2}
    cat.sayHello(); // 动物在叫~
    cat.run(); // 报错})();

3、super

// 超类
(function() {

    // 定义 animal 类
    class Animal {
        name: string;

        constructor(name: string) {this.name = name;}

        sayHello() {console.log('动物在叫~');
        }
    }

   
    class Dog extends Animal {

        age: number;

        constructor(name: string, age: number) {
            // 如果在子类中写了构造函数 在子类函数中必须对父类的构造函数进行调用
            super(name); // 调用父类的构造函数
            this.age = age;
        }

        sayHello() {
            // 在类的办法中 super 示意以后类的父类
            //super.sayHello();
            console.log('汪汪汪');
        }
    }

    const dog = new Dog('小黑', 2);

    dog.sayHello(); // 汪汪汪
    console.log(dog); // Dog {name: "小黑", age: 2}
    


})();

4、抽象类

(function() {

    // 定义 animal 类
    /**
     * 以 abstract 结尾的类是抽象类
     * 抽象类与其余类区别不大 只是不能用来创建对象
     * 抽象类就是专门用来继承的类
     * 
     * 抽象类中能够增加形象办法
    */
    abstract class Animal {
        name: string;

        constructor(name: string) {this.name = name;}

        // 形象办法应用 abstract 结尾 没有办法体
        // 形象办法只能定义在抽象类中 子类必须对起形象办法重写
        abstract sayHello(): void;}

   
    class Dog extends Animal {sayHello() {
            // 在类的办法中 super 示意以后类的父类
            //super.sayHello();
            console.log('汪汪汪');
        }
    }

    class Cat extends Animal { } // 报错 没有实现 s 对 ayHello 重写

    const dog = new Dog('小黑');

    dog.sayHello();
    console.log(dog);
    
    //const ani = new Animal(); // 报错 无奈创立实例})();

5、接口

(function() {

    // 形容一个对象的类型(别名模式)type myType = {
        name: string,
        age: number
    }

    // type myType = {} // 报错 反复申明

    /**
     * 接口用来定义一个类构造,用来定义一个类中应该蕴含哪些属性和办法
     * 接口也可用来当成类型申明去应用
     * 
     * 接口可反复申明
    */

    interface myInterface {
        name: string,
        age: number
    }

    interface myInterface {gender: string}

    const obj: myInterface = {
        name: '哈哈哈',
        age: 12,
        gender: '男'
    }

    /**
     * 接口能够在定义类的时候限度类的构造
     * 接口中的所有属性都不能有理论的值
     * 接口只定义类的构造 而不思考理论值
    */

    interface myInter {
        name: string;

        sayHello(): void;}

    /**
     * 定义类时,能够使类去实现一个接口
     * 实现接口就是使类满足接口的要求
     * 
    */

    class MyClass implements myInter {
        name: string;

        // 须要写构造函数 给 name 赋值
        constructor(name: string) {this.name = name;}

        sayHello() {console.log('大家好');
        }
    }

    const m = new MyClass('嘻嘻');
    m.sayHello(); // 大家好
    console.log(m); // MyClass {name: "嘻嘻"}

})();

// 编译后的 js
"use strict";
(function () {
    const obj = {
        name: '哈哈哈',
        age: 12,
        gender: '男'
    };
    /**
     * 定义类时,能够使类去实现一个接口
     * 实现接口就是使类满足接口的要求
     *
    */
    class MyClass {
        // 须要写构造函数 给 name 赋值
        constructor(name) {this.name = name;}
        sayHello() {console.log('大家好');
        }
    }
    const m = new MyClass('嘻嘻');
    m.sayHello();
    console.log(m);
})();

6、属性的封装

(function() {

    // 定义一个人的类
    class Person {
        // ts 能够在属性前增加修饰符
        /**
         * public 润饰的属性能够在任意地位拜访(批改)默认值
         * private 公有属性 只能在对象外部中拜访(批改)默认值
         * protected 受爱护的属性 只能在以后类和以后类的子类拜访
         * 
        */
        private _name: string;
        age: number;

        constructor(name: string, age: number) {
            this._name = name;
            this.age = age;
        }

        // 定义方法 获取 name 属性
        // getName() {
        //     return this._name;
        // }
        // 定义方法 设置 name 属性
        // setName(value: string) {
        //     this._name = value;
        // }

        // ts 中设置 getter 办法的形式
        get name() {console.log('get name() 办法执行了 ---');
            return this._name;
        }

        set name(value: string) {this._name = value;}
    }
    
    const per = new Person('猴子', 18);

    /**
     * 当初属性是在对象中设置的 属性能够任意被批改
     * 属性被任意批改会导致对象中的数据变得十分不平安
     * 
    */

    //per._age = 20; // 报错 不能拜访
    //per.name = '八戒';

    //console.log(per); // 输入:{name: "八戒", age: 20}

    // per.setName('八戒');
    // console.log(per.getName()); // 输入:八戒

    console.log(per.name); // get name() 办法执行了 ---   猴子
    per.name = '八戒';
    console.log(per.name); // 八戒

    class A {
        protected num: number;

        constructor(num: number) {this.num = num;}
    }

    class B extends A {test() {console.log(this.num);
        }
    }

    const b = new B(123);
    // b.num = 55; // 只能在类“A”及其子类中拜访

    class C {

        // 能够间接将属性定义在构造函数中
        constructor(public name: string, public age: number) {
            this.name = name;
            this.age = age;
        }
    }

    const c = new C('xxx', 123);
    console.log(c); // {name: "xxx", age: 123}

})();

7、泛型

// function fn(a: number): number {
//     return a;
// }

/**
 * 在定义类或函数时 如果遇到类型不明确就能够应用泛型
 * 
*/

function fn<T>(a: T): T {return a;}

// 间接调用具备泛型的函数
const result = fn(123); // 不指定泛型 ts 会主动对类型进行推断
const result2 = fn<string>('hello'); // 指定泛型

// 多个

function fn2<T, K>(a: T, b: K): T {return a;}

const result3 = fn2<number, string>(123, 'hello');

interface Inter {length: number}

function fn3<T extends Inter>(a: T): number {return a.length;}

fn3('122'); // 3
//fn3(123); // 类型“number”的参数不能赋给类型“Inter”的参数
fn3({length: 10}); // 10

// 定义类也能够应用泛型

class MyClass<T> {
    name: string;
    constructor(name: string) {this.name = name;}
}

const c = new MyClass<string>('哈哈哈');
//const d = new MyClass<number>(123); // 类型“number”的参数不能赋给类型“string”的参数

四、我的项目配置

编译选项

1、运行 ts 文件

tsc test.ts

// 监听当个文件 实时编译
tsc test.ts -w

// 监听全副 ts 文件
tsc -w

// 编译所有 ts 文件
tsc

2、tsconfig.json

{
    // 编译器选项
    "compilerOptions": {
        // module 应用类型:none,commonjs,amd,system,umd,es6,es2015...
        "module": "es2015",
        // target 默认 es3
        "target": "ES2015",
        // 开启全副严格模式
        "strict": true,
        // outDir 输入目录
        "outDir": "./dist"
        //lib 用来指定应用的库 个别不必写
        //lib: [],
        // outFile 将全局作用域中的代码合并成一个 用的不多
        "outFile": "./dist/app.js",
        // 是否编译 js 默认 false
        "allowJs": false,
        // 是否查看 js 默认 false
        "checkJs": false,
        // 是否革除正文 默认 false
        "removeComments": false,
        // 不生成编译后的文件
        //"noEmit": false,
        // 当有谬误时不生成编译文件
        "noEmitOnError": false,
        // 设置严格模式
        "alwaysStrict": false,
        // 不容许隐式 any
        "noImplicitAny": false,
        // 是否检测 null
        "strictNullChecks": false
    },
    // 只编译 src 目录下的 ts 文件
    "include": ["./src/**/*"],
    // 不须要被编译的 ts 文件
    "exclude": ["./src/hello/**/*"]
}

3、检测 null

const div = document.getElementById('.div');

if (div !== null) {...}

div?.addEventListener('click', function() {console.log('aaaa');
});

4、我的项目构造

五、应用 webpack 打包 ts 代码

1、装置依赖

// 我的项目初始化
npm init -y

// 装置工具
npm i -D webpack webpack-cli typescript ts-loader

2、webpack.config.js 配置

const path = require('path');

// webpack 中的所有配置信息都应该写到 module.export 中
module.exports = {
    // 入口文件
    entry: "./src/index.ts",
    // 打包文件
    output: {path: path.resolve(__dirname, 'dist'),
        filename: "bundle.js"
    },
    // 打包应用的模块
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: "ts-loader",
                exclude: "/node_modules/"
            }
        ]
    }
};

3、tsconfig.js 配置

{
    "compilerOptions": {
        "module": "ES2015",
        "target": "ES2015",
        "strict": true
    }
}

4、html-webpack-plugin 配置

装置:

npm i html-webpack-plugin -D

配置:

// 引入 html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 配置 webpack 插件
    plugins: [
        new HtmlWebpackPlugin({template: "./src/index.html"})
    ]

5、热更新

装置:

npm i webpack-dev-server -D

配置:

"dev": "webpack serve --open'google chrome'"

运行:

npm run dev

6、clean-webpack-plugin 配置

装置:

npm i clean-webpack-plugin -D

配置:

// 引入
const {CleanWebpackPlugin} = require('clean-webpack-plugin');

// 应用
new CleanWebpackPlugin()

7、模块引入

在 a.ts 中裸露一个变量,而后在 index.ts 去引入,然而在打包过程中会报错,引入 webpack 不能辨认引入的模块,因而须要去设置,须要在 webpack.config.js 中增加 resolve,用来设置模块引入文件的扩展名。

配置:

resolve: {
     extensions: [
         '.ts',
         '.js'
    ]
}

a.ts

export const h: string = '123';

index.ts

import {h} from './a';

console.log(h);

8、babel

npm i @babel/core @babel/preset-env babel-loader core-js -D

六、vue3 + typesctipt

七、学习材料

学习链接:编译选项

在线运行:typescript Playground

退出移动版