一、开发环境搭建
1.下载node.js
2.使用npm全局安装typescript
3.命令 :npm i -g typescript
4.创建TS文件
5.使用tsc对TS文件进行编译:
6.执行命令: tsc xxx.ts
二、TS类型声明
基本类型
number、string、boolean、字面量、any、unknown、void、never、object、array、tuple、enum
语法:
let a:10(字面量)
let 变量 :类型 (let str :string)
let 变量 :类型 = 值 (let a :number = 2)
let function sum (a:number,b:number):number{ return a+b }
如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测
可以使用 | (或)来连接多个类型(联合类型)
let a:number | string
any:表示是任意类型,一个变量设置类型为any,相当于对该变量关闭了TS的类型检测
声明了变量如果不指定类型,则Ts解析器会自动判断变量的类型为any(隐式的any)
unknown:表示未知类型的值(实际是一个类型安全的any)
类型的变量,不能直接赋值给其他变量
let a:unknown a=10;a="str";a=true
类型断言 ,可以用来告诉解析器变量的实际类型
1. 变量 as 类型 ( s = e as string)
2.<类型>变量 (s = <number> 10)
void 用来表示空,以函数为例,表示没有返回值的函数
function fn():void {}
never:表示永远不会返回结果
function fn():never{ thorwerror }
object:表示一个js对象
let a :object;a={};a= function(){}
{}用来指定对象中可以包含哪些属性
?表示可选的
let b:{name:string,age?:number};
[propName:string]:any表示任意类型的属性
let b:{name:string,[propName:string]:any};
设置函数的类型声明,语法:(形参:类型,形参:类型,...)=>返回值
let d:(a:number,b:number)=>number
d= function(n1:number,n2:number):number{}
array数组
语法:1.类型[],2.Array<类型> (let a :Array<number>)
string[]表示字符串数组( let e:string[])
number[]表示数值数组(let g :number[])
元组:固定长度的数组
语法:[类型,类型,...]
let h:[string,string] h= ['123','str']
enum 枚举,将所有可能的情况列举出来
enum Gender {Male = 0,Female = 1}
let i:{name:string,gender:Gender}
i ={name:'str',gender:Gender.Male}
&表示同时
let j:{name:string}&{age:number}
类型别名
type myType = string
let m:myType
三、TS编译选项
自动编译文件 -w
tsc xxx.ts -w
创建tsconfig.json文件,tsc -w 实现自动编译多个文件
{"include": ["./src/**/*"],//用来指定哪些ts文件需要被编译; //**表示任意目录;*表示任意文件"exclude": ["./src/hello/**/*"], //不需要被编译的文件目录"extends": [],//定义被继承的文件"files": [], //指定被编译文件的列表,只有需要编译的文件少时才会用到"compilerOptions": { //编译器的配置"target": "es2015",//用来指定ts被编译为es的版本"module": "es6",//指定要使用的模块化的规范"lib": ["es5", "dom"],//指定项目中要使用的库,一般不更改"outDir": "./dist",//用来指定编译后文件所在的目录"outFile": "./dist/app.js",//用来将代码合并为一个文件;设置outFile后,所有的全局作用域中的代码会合并到同一个文件中"allowJs": true,//是否对js文件进行编译,默认是false"checkJs": false,//是否检查js代码是否符合语法规范,默认是false"removeComments": true, //是否移除注释"noEmit": true,//不生成编译后的文件"noEmitOnError": true,//当有错误时不生成编译后的文件"strict": true,//所有严格检查的总开关"alwaysStrict": true,//用来设置编译后的文件是否使用严格模式,默认false"noImplicitAny": true,//不允许隐式any类型"noImplicitThis": true,//不允许不明确类型的this"strictNullChecks": true,//严格检查空值}
四、使用webpack打包ts代码
1. 项目初始化 npm init -y
2.安装依赖 cnpm i -D webpack webpack-cli typescript ts-loader
3.创建webpack.config.js文件
<script>//引入一个包const path = require('path')//引入html插件const HTMLWebpackPlugin = require('html-webpack-plugin')//引入clean插件const { CleanWebpackPlugin } = require('clean-webpack-plugin')//webpack 中的所有配置信息都应该写在module.exports中module.exports = {entry: "./src/index.ts",//指定入口文件output: { //指定打包文件所在目录path: path.resolve(__dirname, 'dist'),//打包后文件的文件filename: "bundle.js",//告诉webpack不使用箭头函数environment:{arrowFunction:false}},//指定webpack打包时要使用模块module: { //指定要加载的规则rules: [ {//test指定的是规则生效的文件test: /\.ts$/, //要使用的loaderuse: [ {//指定加载器loader: 'babel-loader',//设置babeloptions: {//设置预定义的环境presets: [ [//指定环境的插件"@babel/preset-env",//配置信息{//要兼容的目标浏览器targets:{"chrome":"88","ie":"11"},//指定corejs的版本"corejs":"3",//使用corejs的方式,usage表示按需加载"useBuiltIns":"usage"}]]},},'ts-loader'],//要排除的文件exclue: /node-modules/ }]},//配置webpack插件plugins: [new CleanWebpackPlugin(),new HTMLWebpackPlugin({ title: '这是一个自定义' }),],//用来设置引用模块resolve: { extensions: ['.ts', '.js']}};
</script>
4.创建tsconfig.json文件
{"compilerOptions":{"module":"ES2015","target":"ES2015","strict":true,"outDir":"./dist"},"include":["./src/**/*"]
}
5.package.json 文件下添加"scripts":{"build":"webpack"}
{"name": "webpack","version": "0.1.0","private": true,"scripts": {"build":"webpack""start":"webpack serve --open chrome.exe"},
}
6.执行项目命令 npm run build
7.安装自动生成html文件插件 cnpm i -D html-webpack-plugin
8.安装开发服务器 cnpm i -D webpack-dev-server
package.json 文件下添加"scripts":{"start":"webpack serve --open chrome.exe"}
9.安装插件清空dist文件夹内容,保证每次打包,都是最新的文件
cnpm i -D clean-webpack-plugin
10.安装插件 cnpm i -D @babel/core @babel/preset-env babel-loader core-js
五、面向对象
1.类(class)
/*class 类名{属性名:类型;constructor(参数:类型){this.属性名 = 参数}方法名(){...}
}*/
//例子
//对象中主要包含两个部分:属性、方法
//在属性前使用static关键字可以定义类属性(静态属性),可以直接通过类去调用
//readonly 开头的属性表示一个只读的属性,无法修改
class Person{//定义实例属性name:string = 'aaa';age:number = 12readonly speak:string = 'chinese'static age1: number = 12//构造函数会在对象创建时调用constructor(name:string,age:number){//在实例方法中,this就表示当前的实例。//在构造函数中当前对象是当前新建的那个对象//可以通过this向新建的对象中添加属性this.name = name;this.age = age;}//定义方法say(){//在方法中可以通过this表示当前调用方法的对象console.log('222')console.log(this)}
}
const per = new Person()
console.log(per.age)
console.log(Person.age1)
per.say()
const p = new Person('aaa',12)
console.log()
2.继承
class Parent{name:string;age:number;constructor(name:string,age:number){this.name = namethis.age = age}say(){console.log(22)}
}
/* 使Child类继承Parent类:使用继承后,子类将会拥有父类所有的方法和属性;通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次即可以让所有的子类都同时拥有父类中的方法和属性;如果希望在子类中添加一些父类中没有的方法或属性,直接添加就可以;如果在子类中添加了与父类相同的方法,则子类方法会覆盖掉父类的方法,这种形式叫做方法重写
*/class Child extends Parent{run(){console.log(333)}say(){console.log(22)}
}
const child = new Child(name:'a',age:12)
console.log(child.name)
child.say()
child.run()
3.super关键字
class Animal{name:stringconstructor(name:string){this.name = name}say(){console.log(222)}
}
class Dog extends Animal{age:numberconstructor(age:number){//如果在子类中写了构造函数,在子类构造函数中必须对父类构造函数进行调用super(name);//调用父类的构造函数this.age= age}say(){//在类的方法中super就表示 当前类的父类super.say()}
}
const dog = new Dog(name:'aa',age:12)
dog.say()
console.log(dog)
4.抽象类
/*以abstract开头的类是抽象类;抽象类和其他类区别不大,只是不能用来创建对象;抽象类就是专门用来被继承的类;抽象类中可以添加抽象方法;
*/
abstract class Animal{name:stringconstructor(name:string){this.name = name}/*定义一个抽象方法;抽象方法使用abstract开头,没有方法体抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写*/abstract say():void
}
class Dog extends Animal{age:numbersay(){console.log(222)}
}
const dog = new Dog(name:'aa',age:12)
dog.say()
console.log(dog)
5.接口
/*接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法;同时接口也可以当成类型声明去使用;接口可以定义类的时候去限制类的结构;接口中的所有的属性都不能有实际值;接口只定义对象的结构,而部考虑实际值,在接口中所有的方法都是抽象方法
*/
interface myInterface{name:stringage:numbersay():void
}
const obj:myInterface = {name:'aa'age:12
}
console.log(obj)
/*定义类时,可以使用类去实现一个接口;实现接口就是使用类满足接口的需求
*/
class MyClass implements myInterface{name:stringage:numberconstructor(name:string,age:number){this.name = namethis.age = age}say(){console.log(22)}
}
6.属性的封装
/*TS可以在属性前添加属性的修饰符;public修饰的属性可以在任意位置访问(修改)默认值;private私有属性,只能在类内部进行访问(修改); 通过在类中添加方法使得私有属性可以被外部访问;protected 受包含的属性,只能在当前类和当前类的子类中使用访问(修改)
*/class Person{ private name:stringpublic age:numberconstructor(name:string,age:number){this.name = namethis.age = age}say(){console.log(22)}//定义方法,用来获取属性getName(){return this.name}//定义方法,用来修改属性set(value:string){this.name = value}
}
const per = new Person(name:'aa',age:12)
per.name ='bb'//报错
console.log(per.getName())
per.setName('bbb')class A {protected num :numberconstructor(num:number){this.num = num}
}
class B extends A {test(){console.log(this.num)}
}
const b = new B(123)
b.num = 33//报错class C {//可以直接将属性定义在构造函数中constructor(piblic name:string,public age:number){}
}
const c= new C ('aaa',12)
7.泛型
//在定义函数或是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a:T):T{return a
}
//可以直接调用具有泛型的函数
let res = fn(10) //不指定泛型,TS可以自动对类型进行推断
let res1 = fn<string>('aaa') //指定泛型
//泛型可以同时指定多个
function fn2<T,K>(a:T,b:K):T{console.log(b)
}
fn2<number,string>(123,'aa')interface Inter{length:number
}
//T extends Inter 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a:T):number{return a.length
}class MyClass<T>{name:Tconstructor(name:T){this.name = name}
}
const mc = new MyClass<string>('sss')