一、什么是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"
]
}