一、什么是TypeScript
- 以javaScript 为基础构建的语言,可以在任何支持javaScript的平台中运行,Ts不能被js解析器直接执行,需要将ts文件编译成js文件
- 一个javaScript的超集,TypeScript扩展了JavaScript并添加了类型
二、TypeScript增加了什么
(1)类型
(2)支持ES的新特性
(3)添加Es不具备的新特性
(4)丰富的配置选项
(5)强大的开发工具
三.TypeScript开发环境搭建
> (1)下载node.js,安装node.js > (2)使用npm全局安装TypeScript > ①进入命令行 > ②输入:npm i -g typescript > (3)创建一个ts文件 > (4)适用ts对ts文件进行编译 > ①进入命令行 > ②进入ts文件所在目录 > ③执行命令tsc xxx.ts
复制
四、基本类型
类型声明:
1)类型声明是TS非常重要的一个特点
2)通过类型声明可以指定TS中变量(参数、形参)的类型
3)指定类型后,当为变量赋值时,TS编译器会自动检查是否符合类型声明,符合则赋值,否则报错
4)简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
语法:
let 变量:类型; let 变量:类型 = 值; function fn(参数:类型,参数:类型):类型 { }
复制
自动类型判断:
a.Ts拥有自动的类型判断机制
b.当对变量的声明和赋值是同时进行的,ts编译器会自动判断变量的类型
c.所以如果你的变量的声明和赋值是通过是进行的,可以省略掉类型声明。
类型:
类型 | 例子 | 描述 |
---|---|---|
number | 1,-33,2.5 | 任意数字 |
String | ‘hi’,”h1”,hi | 任意字符串 |
Boolean | True,false | 布尔值true或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
---|---|---|
Any | * | 任意类型 |
Unknown | * | 类型安全的any |
Void | 空值(undefined) | 没有值或undefined |
Never | 没有值 | 不能是任何值 |
Object | {name:’孙悟空’} | 任意的js对象 |
Array | [1,2,3] | 任意js数组 |
Tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
Enum | Enum{A,B) | 枚举,TS中新增类型 |
类型使用样例:
//let a:string // 也可以直接使用字面量进行类型声明 let a:10 // 字面量相当于常量,他不能被修改 // 可以使用|连接多个类型(联合类型) let b:'male' | 'female'; //声明b可以是male 或者female let c:boolean|string; /Any/// // any 表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了ts的类型检测 // 使用TS时,不建议使用any类型 // let d:any; 显式any // 声明变量如果不指定类型,则TS解析器会自动判断类型变量的类型为any(隐式any) let d; d = 10; d = 'hello' d = false d = {} let s:string; // d的类型式any,它可以赋值给任意变量 s = d; // unknown 表示未知类型的值 let e:unknown; e = 10; e = 'hello'; e = true let t:string; // e的类型是unknown未知的类型,将它赋值给已知类型string时会报错:Type 'unknown' is not assignable to type 'string'.ts(2322) // t = e; //unknown 实际上是一个类型安全的any,unknown类型的变量不能直接赋值给其他变量 // 解决办法1: if(typeof e === 'string') { t = e } // 解决办法2:类型断言:可以用来告诉解析器变量的实际类型(意思是我们知道e是字符串,编译器不知道, // 我们告诉编译器它就是字符串,让它放心的用吧) /** * 类型断言: * 语法: * 变量 as 类型 * <类型>变量 */ s = e as string; //或写成 s = <string>e; // void 用来表示返回值为空,以函数为例,就表示没有返回值函数 function fn():void{ // return '123' // 当返回值为void时,会报错Type 'string' is not assignable to type 'void'.ts(2322),可以写成return;或者return undefined;或者return null; } // never 表示永远不会返回结果 function fn2():never{ throw new Error('报错了'); // return '123' // 当返回值为void时,会报错Type 'string' is not assignable to type 'void'.ts(2322),可以写成return;或者return undefined;或者return null; } // object表示一个js对象,不常用,因为万物皆对象, let f:object; f = {}; f = function(){} //object 常用方式如下: // {} 用来指定对象中可以包含哪些属性 // 语法:{属性名:属性类型} // 在属性名后面加上?,表示属性是可选的 let g:{name:string, age?:number} //?表示这个属性后面赋值有也行,没有也行 g={name:'孙悟空'}; // [propName: string]: any 表示任意类型的属性 let h: {name: string,[propName: string]: any} h = {name: '猪八戒', age: 18} /* *设置函数结构的类型声明 语法:(形参:类型,形参:类型...)=>返回值 */ let i:(a:number,b:number)=>number; // i = function (n1, n2):number{ // return n1 + n2; // } /** * 数组的类型声明: * 类型[]; * Array<类型> */ // string[]表示字符串数组 let j:string[]; let k:Array<number>; let l:Array<any>; /** * 元组:元组就是固定长度的数组 * [类型,类型,类型] */ let m:[string,string] m = ['孙悟空','猪八戒'] /** * 枚举 */ enum Gender{ Male = 0, female = 1 } let n:{name:string,gender:Gender} n={ name: '孙悟空', gender: Gender.Male } console.log(n.gender === Gender.Male) //类型的别名 type mytype = 1|2|3|4|5; let r:mytype r=5; //r=6; // Type '6' is not assignable to type 'mytype'.ts(2322)
复制
五、Ts编译配置
项目新建tsconfig.json
{ /*tsconfig.json 是ts编译器的配置文件,ts编译器可以根据她的信息来对代码进行编译 "include": ["],用来指定哪些ts文件需要被编译,一个/*表示任意文件,两个/**表示任意文件目录 "exclude": 不需要被编译的目录,默认值["node_modules","bower_components","jspm_packages"] "extends":"", 继承,如果我有两个tsconfig文件,我又不想在写一份,可以用该属性 "files":[xxx.ts,xxx.ts]指定被编译的文件列表 compilerOptions{} 编译器配置 target: 用来指定ts 编译后的Es版本,默认ES3,,可选值es3,es5,es6,es2015,es2016,es2017,es2018,es2019,es2020,esnext lib[] 用来指定项目中要使用的库,一般不动他 module: 指定要使用的模块化规范,可选值:none commonjs amd system umd es6 es2015 es2020 exnest outDir: 用来指定版以后文件所在的目录 outFile: 将代码合并成一个文件,设置outFile 后 所有的全局作用域中的代码会合并到同一个文件中。 allowJs: 是否对js文件进行编译,默认false checkJs: 是否检查js文件语法 removeComments: 编译时是否去除注释 noEmit: 不生成编译后的文件 noEmitOnError: 当有错误时不生成编译文件 // 语法检查的属性 alwaysStrict: 严格模式,用来设置编译后的文件是否使用严格模式,默认false noImplicitAny: 不允许使用隐式any noImplicitThis: 不允许使用不明确类型this strictNullChecks: 严格的检查空值, strict: 所有严格模式的总开关,这个属性一定要写在最上面 */ "compilerOptions": { "module": "commonjs", "target": "ES5", "sourceMap": true, "outDir": "./dist", // "outFile": "./dist/app.js" "allowJs": false, "checkJs": false, "removeComments": false, "noEmit": false, "noEmitOnError": false, "strict": false, "alwaysStrict": false, "noImplicitAny": false, "noImplicitThis": false, "strictNullChecks": false }, "exclude": [ "node_modules" ], "include": ["./src/**/*"] }
复制
六、Webpack
1.命令行输入:npm init -y 对项目进行初始化。会自动生产package.json文件
2.安装wabpack所需要的依赖 npm i -D webpack webpack-cli typescript ts-loader
其中-D为开发环境,webpack-cli为webpack命令行工具,typescript 包,ts-loder为ts和webpack整合工具
根目录新建wabpack.config.js文件
/ 引入一个包 const path = require('path') // webpack 中的所有的信息都应该写在module.exports中 module.exports = { // 指定入口文件 entry:'./src/index.ts', // 指定打包文件所在目录 output:{ // 指定打包文件的目录 path: path.resolve(__dirname,'dist'), //打包后文件的名字 filename:"bundle.js" }, //指定webpack打包时要使用的模块 module:{ // 指定要加载的规则 rules:[ { // test 指定的时规则生效的文件 test: /\.ts$/, // 要使用的loader use: 'ts-loader', // 要排除的文件 exclude: /node_modules/ } ] } }
复制
3.新建tsconfig.json文件
{ "compilerOptions": { "module": "ES2015", "target": "ES2015", "strict": true } }
复制
4.在package.json文件中的scripts加入build:webpack属性用于打包
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" },
复制
5.后续使用npm run bulid进行打包编译
命令行执行npm i -D html-webpack-plugin,帮助我们自动生成html文件
1.webpack.config.js 引入webpack-plugin
// 引入html插件 const HTMLWebpackPlugin = require('html-webpack-plugin') //在module.exports中添加如下代码,template为自定义html,如过没有该属性,它会在编译时自动创建一个html plugins:[ new HTMLWebpackPlugin({ // title: "这是自定义的title" template:"./src/index.html" }) ] }
复制
2.Webpack开发服务器: npm i -D webpack-dev-server
安装完之后,在package.json的scripts属性下添加start:”webpack serve --open chrome.exe”
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open chrome.exe" },
复制
使用npm run start进行编译,编译完成后自动打开谷歌浏览器
3.npm i -D clean-webpack-plugin ,每次在编译时都会先清空dist文件夹,保证每次都是最新的文件
安装完后,在webpack.config.js文件下引入:
/ 引入clean插件
const {CleanWebpackPlugin } = require('clean-webpack-plugin') // 并在plugins下添加 plugins:[ new CleanWebpackPlugin(),... ]
复制
4.引用模块编译报错,如使用import引入某个js 或ts,编译时会出错,需要在webpack.config.js加入如下配置
/ 用来设置引用模块 resolve:{ extensions:['.ts','.js'] }
复制
Bable 解决兼容性问题,tsconfig可以设置es版本,它只是语法上的转换,bable可以兼容不同的浏览器,
npm i -D@babel/core @babel/preset-env babel-loader core-js
安装完成后,打开webpack-config.js
在module.rules下use改为
//指定webpack打包时要使用的模块 module:{ // 指定要加载的规则 rules:[ { // test 指定的时规则生效的文件 test: /\.ts$/, // 要使用的loader use: [{ // 指定加载器 "loader":"babel-loader", // 设置bable Option:{ // 设置预定义的环境 presets:[ [ // 指定环境的插件 "@babel/preset-env", // 配置信息 { // 要兼容的目标浏览器 targets: { "chrome": "88", "ie":"11" }, // 指定corejs的版本 "corejs":"3", // 使用corejs的方式,‘usage’表示按需加载 "useBuiltIns":'usage' }] ] } },'ts-loader'], //它是由后向前执行,先将ts转换为js,在将js转换为浏览器兼容的js版本 // 要排除的文件 exclude: /node_modules/ } ] },
复制
Webpack 打包时不在最外层添加箭头函数,ie不支持箭头函数。
在webpack-config.js,在output下添加environment属性
output:{ // 指定打包文件的目录 path: path.resolve(__dirname,'dist'), //打包后文件的名字 filename:"bundle.js", // 告诉webpack 打包时不使用箭头函数 environment:{ arrowFunction: false } },
复制
七、面向对象
面向对象是程序中一个非常重要的思想,它被很多同学理解成了一个比较难,比较深奥的问题,其实不然,面向对象很简单,简而言之,就是程序之中所有操作都需要通过对象来完成。
举例说明:
1.操作浏览器要使用window对象
2.操作网页要使用docurment对象
3.操作控制台要使用console对象
一切操作都需要对象,也就是所谓的面向对象,那么对象到底是什么呢? 这就要先说到程序是什么,计算机程序的本质就是对显示十五的抽象,抽象的反义词就是具体,比如,照片是对一个具体人的抽象,汽车模型是对具体汽车的抽象,程序也是对事物的抽象,在程序中我们可以表示一个人,一条狗,一把枪,一颗子弹等等所有事物,一个事物到了程序中就变成了一个对象。
在程序中,所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名,性别,年龄,身高,体重等属于数据,人可以说话,走路,吃饭睡觉这些属于人的功能,数据在对象中被成为属性,而功能就被称为方法,所以简而言之,在程序中一切皆是对象。
1.类(class)
要想面向对象操作对象,首先要拥有对象,那么下一个问题就是如何创建对象,要创建对象,必须要先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象,举例来说:可以通过person类来创建人的对象,通过Dog类可以创建狗的对象,通过Car类来创建汽车的对象,不同的类可以用来创建不同的对象。
/ 使用class关键字来定义一个类 /** * 对象中主要包含了两个部分 * 属性 * 方法 */ class Person{ /* 直接定义的属性是实例属性,需要通过对象实例去访问: const per = new Person(); console.log(per.name) 使用static开头的属性是静态属性(类属性) console.log(Person.age) readonly 开头的属性,表示只读的属性,不能修改 */ // 定义实例属性 name: string = '孙悟空'; // 在属性前使用static 关键字可以定义类属性(静态属性) static age: number = 18; // 定义方法 /** * 如果方法以static开头,则方法就是类方法,可以直接通过类调用 */ sayHello(){ console.log('hello 大家好!') } } const per = new Person(); console.log(per.name) console.log(Person.age) per.sayHello()
复制
2.构造函数和this
class Dog { name:string; age:number; // constructor被称为构造函数 // 构造函数会在对象创建时调用 constructor(name:string,age:number){ console.log('构造函数执行了~~~') //在实例方法中this就表示当前的实例, // 在构造函数中当前对象就是当前新建的那个对象 console.log(this) this.name=name this.age=age } bark() { // alert('汪汪汪') // 在方法中可以通过this来表示当前调用方法的对象 console.log(this.name) } } const dog1 = new Dog('小黑',19) const dog2 = new Dog('小白',2) console.log(dog1) dog1.bark() // 小黑 dog2.bark() // 小白
复制
3.继承和重写
class Animal { name: string; age: number; constructor(name:string,age:number){ this.name=name; this.age=age; } sayHello(){ console.log("嘎嘎嘎") } } // 表示猫的类 class Cat extends Animal{ // sayHello(){ console.log('喵喵喵') } } /** * Dogs extends Animal * -此时,Animal被称为父类,Dog被称为子类 * - 使用继承后,子类将会拥有父类所有的方法和属性 * - 通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次即可让所有子类都同时拥有父类的属性, * -如果希望在子类中添加父类没有的属性或方法,直接加就行 * - 如果在子类中添加了和父类相同的方法,则子类方法会覆盖父类的方法 * 这种子类覆盖父类方法的形式,我们称为重写 */ // 表示狗的类 class Dogs extends Animal{ run(){ console.log(this.name + "哈利波特骑着扫帚飞~") } sayHello(){ console.log('汪汪汪') } } const cat = new Cat("小黑猫",4) const dogs = new Dogs("小黑猫",4)
复制
4.Supper
class Animal{ name: string constructor(name:string){ this.name=name } sayHello(){ console.log('hahaha') } } class Dog extends Animal { age: number constructor(name:string,age:number){ // 如果在子类中写了构造函数,在子类构造函数中必须调用父类构造函数supper() super(name) // 调用父类的构造函数 this.age = age } sayHello() { // 在类方法中,super就表示当前类的父类 super.sayHello() } }
复制
5.抽象
/** * 以abstract开头的类是抽象类, * 抽象类和其他类区别不大,只是不能用来创建对象 new Animal, * 它生下来就是给人当爸爸的,抽象类就是专门用来被继承的类 * * 抽象类中可以添加抽象方法, */ abstract class Animal{ name: string constructor(name:string){ this.name=name } // 定义一个抽象方法,以abstract开头,没有方法体 // 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写; abstract sayHello():void; } class Dog extends Animal { sayHello() { console.log('汪汪汪') } } class Cat extends Animal { sayHello() { console.log('喵喵喵') } }
复制
6.接口
// 描述一个对象的类型 type myType = { name: string, age: number } const obj:myType ={ name: 'aaa', age: 12 } /** * 接口用来定义一个类的结构,用来定义一个类中应该包含哪些属性和方法 * 同时接口可以当成类型声明去声明, */ interface myInterface { name: string, age: number } interface myInterface { gender: string } const obj1:myInterface ={ name: 'aaa', age: 12, gender: '男' } /** * 接口可以在定义类的时候去限制类的结构 * 接口中的所有的属性都不能有实际的值 * 接口只定义对象的接口,而不考虑实际值 * 在接口中所有的方法都是抽象方法 */ interface myInter { name: string; sayHello():void; } /** * 定义一个类时,可以使用类去实现一个接口 * 实现接口,就是使类满足接口的要求 */ class MyClass implements myInter{ name: string; constructor(name:string) { this.name = name } sayHello(): void { console.log('大家好') } }
复制
7.属性的封装
// 定义一个表示人的 类 class Person { // TS可以在属性前添加属性的修饰符 /** * public 修饰的属性可以在任意位置访问(修改)默认值 * private 私有属性,私有属性只能在类内部进行访问(修改) * - 可以通过类中添加方法,使得私有属性可以被外部访问 * protected 受保护的属性,只能在当前类和当前类的子类中访问(修改) */ private _name:string; private _age:number; constructor(name:string,age:number){ this._name=name; this._age=age; } /** * * getter 用来读取属性 * setter 用来设置属性 * -它们被称为属性的存取器 */ // 定义方法,用来获取name属性 // getName() { // return this._name // } // // 定义方法,用来设置name属性 // setName(name:string) { // return this._name = name // } // // 定义方法,用来获取name属性 // getAge() { // return this._age // } // // 定义方法,用来设置name属性 // setAge(age:number) { // if(age >= 0) { // return this._age = age // } // } // TS中设置getter方法的方式 // 用起来和属性一样 console.log(per.name) get name(){ return this._name } // 用起来和属性一样 per.name = '猪八戒' set name(name:string) { this._name = name } } const per = new Person('孙悟空', 8) /** * 限制属性是在对象中设置的,属性可以任意的被修改 * 属性可以任意被修改将会导致对象中的数据非常不安全 */ // per._age = 38 // per.getName() // per.setName('猪八戒') console.log(per.name) per.name = '猪八戒'
复制
语法糖
class A{ num:number; constructor(num:number){ this.num =num } }
复制
可写成
class A{ constructor(public num:number){ } }
复制
8.泛型
// function fn(a:number):number{ // return a // } /** * 在定义函数或是类时,如果遇到类型不明确就可以使用泛型 * T可以写其他字母都可以,它代表不明确类型,只有代码执行的时候,传进来什么类型就是什么类型 */ function fn<T>(a: T):T{ return a } // 可以直接调用具有泛型的函数 fn(10) // 不指定泛型,TS可以自动对类型进行推断 fn('10') fn(false) fn<string>('hello') // 指定泛型, // 泛型可以直接指定多个 function fn2<T,K>(a:T,b:K):K{ return b } fn2<number,string>(123,'344'); interface Inter { length: number; } // T extends Inter 表示泛型T必须是Inter实现类(子类) function fn3<T extends Inter>(a:T):number{ return a.length } fn3({length: 10}) class MyClass<T> { name: T; constructor(name:T){ this.name = name } } const mc = new MyClass<string>('孙悟空') const mc1 = new MyClass(123)
复制
9.安装css 解析器 npm i -D less less-loader css-loader style-loader
在wabpace.config.js中 module下加入
{ test: /\.less$/, use: [ "style-loader", "css-loader", "less-loader" ] }
复制
css兼容性处理:
npm i -D postcss postcss-loader postcss-preset-env
{ test: /\.less$/, use: [ "style-loader", "css-loader", // 引入postcss { loader: "postcss-loader", options: { postcssOptions:{ plugins: [ ["postcss-perset-env", { browsers: 'last 2 versions' // 兼容两个最新版本的浏览器 }] ] } } }, "less-loader" ] }
复制