一、简介

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' }// 编译后的jsvar 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}// 编译后的jsvar 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}// 编译后的jsvar 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' }// 编译后的jsvar 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 类型是stringtype myType2 =  1 | 2 | 3 | 4;k = 1;k = 6;//报错

8、function

//js不思考参数的类型和个数的function sum(a, b) {  return a + b;};// ts 隐式anyfunction sum(a: any, b:any):any {    return a + b;};function sum2(a:number, b:number): number {    return a + b;};let s1 = sum('1', 2); // 12let s2 = sum(2, 2); // 4let s3 = sum2(1, 5); // 6console.log(s1, s2, s3);

9、任意值

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

any

//any示意任意类型的值,一个类型应用了any后相当于敞开了ts的类型检测//在应用ts时 不倡议应用anylet a: anya = 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: unknownc = 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); //falselet 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-pluginconst 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