Author: @德玛玩前端
Date: 2023-06-07
TypeScript
一、Typescript介绍
1.1、TypeScript产生的原因
- 旧JS是弱类型语言,一个变量先后可以保存不同类型的数据,所以不可靠。
- 旧JS是解释执行语言,一边解释,一边执行,一些低级错误无法提前检查和预警。
- 旧JS对对象要求不够严格,开发人员想怎么写怎么写,不便于大项目写作。
1.2、TypeScript介绍
- TypeScript是JavaScript的一个超集
- 支持ECMAScript6标准
- TypeScript由微软开发
- 设计目的是开发大型应用
1.3、新特性
- 类型检查
- 编译时错误检查
- 接口
- 访问修饰符
- 模块
二、TypeScript编译器
- TypeSCript不能被浏览器直接执行
- TypeScript可以编译成纯JavaScript
- 编译出来JavaScript可以运行在任何浏览器或nodejs上
2.1、TypeScript 安装和配置
- 首先安装node 环境
npm i -g typescript
全局安装TypeScript语言的编辑器
2.2、手动编译
// 1.ts
let a:number=10;
console.log(a)
↓
// TS编译器,类型检查,低级错误检查
↓
//2.js
"use strict"
var a=10
console.log(a)
-
新建 文件 1.ts
-
再编译ts文件为js文件
打开命令行窗口,输入
tsc 1.ts
编译后会得到一个 ES5 版本的 js 文件 例如
tsc --target ES5 test.ts
-
tsc编译器将.ts文件的内容翻译为等效的js文件,保存在ts文件旁边的同名1.js文件中
-
注意:生成的js文件进行修改就不归编译器管了,所以js文件不允许修改;
ts只是开发阶段,来规范,限制的标准而已,实际上将来的运行的还是js文件
2.3、自动编译
-
tsc -init
生成tsconfig.json文件。里面保存的是ts编译为js时所需的配置{ "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ "target": "es5", //将ts编译为es5版本的js,适配多个浏览器 /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "module": "commonjs", //将来ts文件中模块化开发所采用的标准 /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ // "outDir": "./", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ "strict": true, //将ts编译为js文件时,自动启用严格模式 /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ } }
-
在vscode中选择
终端
->运行生成任务
->tsc:监视xxx
-
结果:只要修改ts文件,一保存,就自动编译,自动创建js文件
-
不输入命令,运行js文件
- 1.先打开要运行的js文件
- 2.点左边小虫+三角图标
- 3.点运行和调试
- 4.选择nodejs
- 5.看到执行结果
-
如果想把 ts 文件编译完成后放在 js 文件目录中,修改tsconfig.json中得配置。
"outDir": "./js", /* 把 ts 文件编译完成后放在 js 文件目录中,没有会自动创建。 */
三、TypeScript的语法
3.1、变量
-
旧js是弱类型语言,一个变量先后可以保存不同类型的数据,不可靠。
-
今后,只要在ts中声明变量,都必须用"数据类型"来规定
-
标准语法:
var
或const
或let
变量名:数据类型=初始值 -
结果:将来这个变量只能保存规定的数据类型
-
变量的数据类型提前声明,不同类型的变量相互赋值会报错,比如:
let a:number=10
a='hello'
报错:不能将类型 “string” 分配给类型 “number” -
基本类型:boolean,number,string
-
数组:2种写法,结果一样
- let 数组名:数据类型[]=[值1,值2,值3,…]
- let 数组名:Array<数据类型>=[值1,值2,…]
- any:可以匹配任何数据类型
let arr:string[]=['hu','wen','haha'] console.log(arr); //arr[0]=100;//报错,因为规定数组里的都为字符串 let arr1:Array<number>=[1,2,23,4] console.log(arr1); arr1[0]=100 // arr1[0]="100" //报错,因为规定数组里的都有数字
3.2、函数 Function
-
既没有参数,又没有返回值的函数,与普通写法一样。
-
如果函数有返回值
function 函数名():返回值的类型{ ... return 返回值 (实际返回值的类型与声明函数的时:后的返回值类型返回一致)。 }
-
如果函数有参数
function 函数名(形参1:数据类型,形参2:数据类型,..){ //强调:ts中严格规定,一个函数定义了几个形参,就必须传几个实参,数据类型也要对应 }
-
如果既有形参,又有返回值
function 函数名(形参1:数据类型,形参2:数据类型,...){ ... return 返回值 }
-
可选参数
- ?表示参数可以没有。将来如果没有传入这个参数值,则参数值默认为undefined
function 函数名(形参1:数据类型,形参2?:数据类型){ ..... }
-
默认值
function 函数名(形参1:数据类型,形参2:数据类型=默认值){ //默认值保证不传之的情况下,一定有值可用。 }
-
实参值个数不确定
function 函数名(固定形参:数据类型,...数组名:数据类型[]){ }
3.2.1、函数的重载
重载:只定义一个函数,根据传入不同的参数,执行不同的逻辑。
-
js,只定义一个函数,在函数内根据传入的参数不同,执行不同的逻辑
function pay(){ if(argruments.length==0){ 手机支付 }else if(arguments.length==1){ 现金支付 }else{ 刷卡支付 } } pay() pay(100) pay('6553 1234','123456')
-
ts中需要两步来实现
-
ts中先定义多个同名函数的声明,只要形参列表不同即可!但是不要实现函数体
- function 函数名():void
- function 函数名(形参:数据类型):void
- 强调:这里只是不同重载版本的声明,不包括函数定义
- void代表这个函数没有返回值
- 如果函数有返回值,则必须将void改为返回值的具体类型
-
定义一个可实际执行多种任务的函数来支持上方多种重载的情况
function 函数名(形参?:数据类型){ if(形参===undefined){//说明用户调用的是第一个重载版本 //没有传入任何实参 //就执行一项操作 }else{ //说明用户调用的是第二个重载版本,传了一个实参 //就执行另一项操作 } }
-
执行
函数名()
函数名(参数)
// 定义可能出现的情况 function pay():void function pay(money:number):void function pay(cardId:string,pwd:string):void //实现重载的几种可能 function pay(...arr:Array<any>){ if(arr.length==0){ console.log('手机支付'); }else if(arr.length==1){ console.log(`现金支付,收您${arr[0]}元`); }else{ console.log(`刷卡支付,从您卡号${arr[0]}扣款成功`); } } // function pay(a?:any,b?:any){ // if(a===undefined){ // console.log('手机支付'); // }else if(b===undefined){ // console.log(`现金支付,收您${a}`); // }else{ // console.log(`刷卡支付,从您卡号${a}扣款成功`); // } // }
-
3.3、类 class
-
类名都用大驼峰
-
定义class
class 类型名{ // 强调,ts中class的属性,必须在构造函数外部上方提前定义,并指定数据类型,给初始值,才能在构造函数中this.属性名=赋值 属性名1:数据类型=初始值 属性名2:数据类型=初始值 // constructor的形参也需要给数据类型 constructor(形参1:数据类型,形参2:数据类型){ this.属性名1=形参1 this.属性名2=形参2 } 方法名():数据类型{...} }
-
案例
class Student{ sname:string=""; sage:number=0; constructor(sname:string,sage:number){ this.sname=sname this.sage=sage } intr(){ console.log(`I am ${this.sname},I am ${this.sage}`); } } var lilei =new Student("LiLei",11) as any; // 加 as any是可以在ts中用lilei[key],在ts中只能用arr[index]访问数组 console.log(lilei) for(var key in lilei){ console.log(`${key}:${lilei[key]}`); }
3.4、类的继承
-
子类型class
class 子类型名 extends 父类型名{ 子类型属性:数据类型=初始值; constructor(形参1:数据类型,形参2:数据类型,参数3:数据类型){ super(形参1,形参2) this.子类型属性=形参3 } 方法名:数据类型() }
-
示例
//定义父类型 class Player{ x:number=0; y:number=0; constructor(x:number,y:number){ this.x=x this.y=y } fly(){ console.log(`气球在x=${this.x},y=${this.y}位置`) } } class Balloon extends Player{ // 属于子类的属性也需要载构造函数上方提前定义。 score:number=0; constructor(x:number,y:number,score:number){ super(x,y); this.score=score } getScore(){ console.log(`击中气球,得${this.score}`); } } var p1=new Balloon(50,100,5) as any console.log('p1',p1); for(var key in p1){ //for in 会把原型链中的方法也遍历出来 console.log(`${key}:${p1[key]}`); } p1.fly() p1.getScore()
3.5、访问修饰符
-
在ts中,class中的所有数据,默认是public,所以在class内,子类,全局都可以用"this.属性名"或"父对象.属性名"方式访问到,没有限制。但有些数据不想让人轻易访问到,所以用到访问修饰符,可以修饰类中的属性和方法的使用范围。
-
class中对于属性保护的不同级别 public protected private
在声明初始值时就设置
访问控制修饰符 属性名:数据类型=初始值
3.5.1、public 公有(默认),表示子类和类外部都可以访问到的类成员
class Famliy{
public moneyPublic:string="可公开的钱"
fatherPay(){
console.log(`爸爸花${this.moneyPublic}`);
}
}
class Son extends Famliy{
SonPay(){
console.log(`儿子花${this.moneyPublic}`);
}
}
var f1=new Famliy()
console.log('兄弟姐妹用'+f1.moneyPublic);
3.5.2、protected 受保护,表示只有父子类型范围内才能使用,外部不能用
class Famliy{
protected moneyPublic:string="可公开的钱"
fatherPay(){
console.log(`爸爸花${this.moneyPublic}`);
}
}
class Son extends Famliy{
SonPay(){
console.log(`儿子花${this.moneyPublic}`);
}
}
var f1=new Famliy()
console.log('兄弟姐妹用'+f1.moneyPublic); //报错
3.5.3、private 私有,表示仅class内可用,子类型和外部都不能用
class Famliy{
private moneyPublic:string="可公开的钱"
fatherPay(){
console.log(`爸爸花${this.moneyPublic}`);
}
}
class Son extends Famliy{
SonPay(){
console.log(`儿子花${this.moneyPublic}`);//报错
}
}
var f1=new Famliy()
console.log('兄弟姐妹用'+f1.moneyPublic); //报错
3.6、接口
-
问题:在团队开发中,上级分配开发任务给下级,如何保证下级一定按上级要求实现功能
-
解决:开发人员按照架构师的要求实现程序时,通过接口来规范
-
如何实现
//定义接口 interface l接口名{ 规定的属性名:类型 规定的方法名(参数:数据类型):返回值 } //具体实现的人要"实现接口",定义一个符合接口要求的class class 类型名 implements I接口名{ 必须包含接口中规定的属性和方法 }
-
案例
// 上级 interface IStudent{ sname:string; sage:number; intr():void } class Student2 implements IStudent{ sname: string=""; sage: number=0; constructor(sname:string,sage:number){ this.sname=sname this.sage=sage } intr(): void { console.log(`I am ${this.sname},I am ${this.sage}`); } } var wenhao=new Student2("hwwenhao",11) console.log('wenhao',wenhao); wenhao.intr()
-
如何快速使用定义的接口
鼠标悬浮在 类名上,点击 快速修复
点击 实现接口
实现接口
class Student2 implements IStudent{ sname: string; sage: number; intr(): void { throw new Error("Method not implemented."); } }