一、内容概要
- 强类型与弱类型
- 静态类型与动态类型
- JavaScript 自有类型系统的问题
- Flow 静态类型检查方案
- TypeScript 语言规范与基本应用
二、强类型和弱类型(类型安全)
- 强类型(TypeScript):
- 语言层面限制函数的实参类型必须与形参类型相同。
- 更强的类型约束。
- 强类型中不允许有任意的隐式类型装换。
- 弱类型(JavaScript):
- 弱类型语言层面不会限制实参的类型。
三、动态类型和静态类型(类型检查)
- 静态类型(TypeScript):
- 一个变量在声明时,它的类型就是确定的。
- 声明过后,它的类型就不允许再被修改。
- 动态类型(JavaScript):
- 运行阶段才能确定变量的类型。
- 变量的类型能够随时发生变化。
四、JavaScript 类型系统特征
- JavaScript 是一门弱类型和动态类型的语言。
- JavaScript 是一门脚本语言,没有编译环节。
五、弱类型的问题
- 弱类型只有在编译时才能发现问题。
- 类型没有确定,容易发生一些错误。
- 对对象错误的用法。
六、强类型的优势
- 错误可以更早的暴露。
- 代码更加智能,编码更准确。
- 重构更牢靠。
- 减少不必要的类型判断。
七、Flow
1.概述
-
Flow 是 JavaScript 的一款静态类型检查器
-
类型注解
function sum (a:number, b: number) { return a + b; }
2.Flow 快速上手
-
安装 Flow (类型检查)
// 命令行中先初始化,以包的形式去安装 yarn init --yes // 初始化 yarn add flow-bin // 安装flow // vscode 移除编辑器自带的错误检查 ctrl + , 打开弹框,查找处输入 javascript validate 多选框的钩给去掉。 flow init // 初始化flow yarn flow // 执行flow 进行类型验证
-
在 .js 文件中需要 flow 进行类型检查,需要在头部添加 // @flow 标记
3.Flow 编译移除注解
-
通过 flow-remove-types 移除注解
// 安装 flow-remove-types 插件 yarn add flow-remove-types --dev // 移除注解 yarn flow-remove-types . -d dist // . 是当前目录 dist执行后的文件
-
通过 babel 移除注解
// 安装 babel 包 yarn add @babel/core @babel/cli @babel/preset-flow --dev // 添加 babel 配置文件 .babelrc 文件 // 文件中配置 {"presets":["@babel/presets-flow"]} yarn bable src -d dist
-
Flow 在vscode 中开发工具插件 Flow Language Support 安装,每次保存过后自动检查类型错误。
八、TypeScirpt
1.TypeSript介绍:
- TypeScript 是微软开发的一款开源的编程语言。
- TypeScript 是 JavaScript 的超集,遵循了最新的 es5、es6 规范。TypeScript 扩展了 JavaScript 的语法。
- TypeScript 更像后端 Java、C# 这样的面向对象语言,可以让 JS 开发大型企业项目。
- 谷歌也在大力支持 TypeScript 的推广,谷歌的 Angular2.x+ 就是基于 TypeScript 语法。
- 最新的 Vue 、React 也可以集成 TypeScript。
- Nodejs 框架 Nestjs、midaway 中用的就是 TypeScript 语法。
2.TypeScript 安装、编译
-
安装
// npm 安装 npm install -g typescript // cnpm 安装 cnpm install -g typescript // yarn 安装 yarn global add typescript
-
编译
// 命令行: tsc helloWorld.ts // 安装 ts-node插件 ts-node helloWorld.ts
3.Vscode 自动编译 .ts 文件
-
创建 tsconfig.json 文件 tsc --init 生成配置文件
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NbaGvOv-1619423482612)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210412094932887.png)]
-
老版本 vscode 点击: 任务->运行任务-> tsc:监视-tsconfig.json 然后就可以自动生 成代码了
-
最新版本 vscode 点击: 终端->运行任务->typescript->tsc:监视-tsconfig.json 然后就 可以自动生成代码了
九、TypeScript 中的数据类型
1.TypeScript 数据类型
- TypeScript 中为了使编写的代码更规范,更有利于维护,增加了类型校验。
- 布尔类型(boolean)
- 数字类型(number)
- 字符串类型(string)
- 数组类型(array)
- 元组类型(tuple)
- 枚举类型(enum)
- 任意类型(any)
- null 和 undefined
- void 类型
- never 类型
2.定义类型示例
-
布尔类型
let bool: boolean = true;
-
数字类型
let num: number = 11;
-
字符串类型
let str: string = 'lin';
-
数组类型
// 第一种定义方式 let arr: string[] = ['lin','xing']; // 第二种定义方式: 泛型 let arr: Array<string> = ['lin','xing']; // 第三种类型: let arr: any[] = ['linxing', 123, false];
-
元组类型
let tup: [string, number, boolean] = ['JavaScript', 110, true];
-
枚举类型
enum 枚举名{ 标识符[= 整型常数], 标识符[= 整型常数], .... 标识符[= 整型常数], } enum Flag{ success = 1, error = 2}; let f:Flag = Flag.success; console.log(f); // 结果1
-
任意类型
let anyType: any = 'string' // 什么类型都能放
-
null 和 undefined 类型
let age: number | undefined; // | 或者的意思 let num: number | null | undefined;
-
void 类型
// void 表示没有任何类型,一般用于执行方法没有返回值 function sum(x, y,): void{ let num: number = x+y; }
-
never 类型
// never类型:是其他类型(包括 null 和 undefined )的子类型,代表从不会出现的值。 // 这意味着声明never的变量只能被never类型所赋值。
十、TypeScript 函数
1.TypeScript函数
-
es5中定义方法
// 函数声明式 function sun() {}; // 匿名函数 let person = function(){};
-
TypeScript中定义方法
// 函数声明式 function sun():viod{}; // 匿名函数 let person = funciton():string{ return ''}
2.函数方法传参
-
函数声明
function getInfo(name: string, age: number): string{ return `我的名字叫${name},今年${age}岁` }
-
匿名函数
let getInfo = function(name: string, age: number): viod{ console.log(`我的名字叫${name},今年${age}岁`) }
3.方法的可选参数
-
es5 里面方法的实参和形参可以不一样,但是 ts 中必须一样,如果不一样就需要配置可选参数
-
注意!可选参数必须配到参数的最后面
let getInfo = function(name: string, age?: number): viod{ if(age){ console.log(`我的名字叫${name},今年${age}岁`) }else{ console.log('哈哈哈') } }
4.方法的默认参数
-
es5 中是不能配置默认传参的,es6 和 ts 可配置默认参数
let getInfo = function(name: string, age: number = 23): viod{ if(age){ console.log(`我的名字叫${name},今年${age}岁`) }else{ console.log('哈哈哈') } }
5.函数剩余参数
-
三点运算符 接收传递过来的所有参数
function sum(a:number, ...result: number[]): number{ var sum = 0; for(let i = 0; i<result.lenght;i++){ sum+=result[i]; } return sum }
6.函数重载
-
java 中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
-
typescript 中的重载:通过为同一个函数提供多个函数类型定义来试下各种功能的目的。
-
为了兼容es5,以及es6中重载的写法和java有区别
function getInfo(names: string): string; function getInfo(age:number ): string; function getInfo(str:any):any { if(typeof str === 'string'){ return `我叫:${str}` }else{ return `我的年龄是${str}` } }
十一、TypeScript 中的类
class Person{
name:string;
constructor(name: string){ // 构造函数 实例化类的时候触发的方法
this.name = name;
}
getName(): string{
return this.name
}
setName(name:string):viod {
this.name = name;
}
}
1.TypeScript 中类继承
// extends、super
class Person{
name:string;
constructor(name: string){ // 构造函数 实例化类的时候触发的方法
this.name = name;
}
getName(): string{
return this.name
}
setName(name:string):viod {
this.name = name;
}
}
定义 web 类来继承 Person 类
class Web extends Person{
constructor(name:string){
super(name) // 初始化父类的构造函数
}
}
let w = new Web('李四');
2.TypeScript类里面的修饰符
- TypeScript 里面定义了属性的时候给我们提供了三种修饰符
- public:公有 在类里面、子类、类外都可以访问
- protected:保护类型 在类里面、子类里面可以访问,在类外部没法访问
- private:私有 在类里面可以访问,子类、类外部都没法访问
- 属性不加修饰符:默认代表共有属性,public
class Person{
public name:string;
constructor(name: string){ // 构造函数 实例化类的时候触发的方法
this.name = name;
}
getName(): string{
return this.name
}
setName(name:string):viod {
this.name = name;
}
}
十二、TypeScript 中类的静态属性、静态方法、抽象类、多态
1.es5中的静态属性、静态方法
function Person(){}
Person.name = 'linxing'; // 静态属性
Person.sayName = function(){ console.log(this.name) } // 静态方法
Jquery
$(.box).css();
function $(el){ return Base(el)}
Base(){ this.css = '获取DOM节点'}
2.TypeScript中静态属性、静态方法
class Person{
public name: string
static age: number
constructor(name:string){
this.name = name
}
sayName(){ // 实例方法
}
static print(){ // 在静态方法里面不能使用this
console.log('我这是静态方法')
}
}
3.多态方法
- 父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现
- 多态属于继承
class Animal{
name: string
constructor(name:string){
this.name = name
}
eat(){ // 定义了一个方法不去实现,让子类去实现
console.log('我是吃的方法')
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){ // 这就是多态, 继承重写了父类方法
console.log('小狗吃粮食')
}
}
class Cat extends Animal {
constructor(name:string){
super(name)
}
eat(){
console.log('吃老鼠')
}
}
4.抽象方法
- typeScript 中的抽象类:它是提供其他类继承的基类,不能直接被实例化。
- 用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
- abstract 方法只能放在抽象类里面
- 抽象类和抽象方法用来定义标准,标准:Animal 这个类要求它的子类必须包含 eat 方法
abstract class Animal{ // 父类定义,子类必须实现
public names: string
constructor(name:string) {
this.names = name;
}
abstract eat():any;
}
// let p = new Animal() 错误:无法定义抽象类
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){
console.log(this.names + '吃');
}
}
十三、TypeScrip 中的接口
1.接口的概念
- 接口的作用:在面向对象的编程中,接口时一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescript 中的接口类似于 java ,同时还增加了更灵活的接口类型,包括属性、函数、可索引、和类等。
- 定义行为和动作的规范。对批量方法进行约束 interface
2.属性类接口
-
就是传入对象的约束 属性接口
interface FullName{ firstName: string; // 注意,分号结束 secondName: string; } function printName(name:FullName){ // 必须传入firstName secondName console.log(name.firstName + name.secondName) }
-
可选接口
interface FullName(){ firstName: string; secondName?:string } function getName(name:FullName){ console.log(name) } // 参数的顺序可以不一样 getName({ firstName:'linxing'; secondName:'liner' })
-
示例
interface Config{ type: string; url: string; data?: string; dataType: string } function ajax( config: Config ){ var xhr = new XMLHttpRequest(); xhr.open( config.get, config.url, true); xhr.send(config.data); xhr.onreadystatechange = function(){ if(xhr.readyState === 4 && xhr.status == 200){ if(confiig.dataType == 'json'){ JSON.perse(xhr.responseText) }else{ console.log(xhr.reponseText) } } } } ajax({ type:'get', data:'name:zhang', url: 'http://www.baidu.com', dataType:'json' })
3.函数类接口
-
函数类型接口:对方法传入的参数 以及返回值进行约束 批量约束
-
加密的函数类型接口
interface encrypt{ (key:string,value:string):string; } var md5:encrypt = function (key:string,value:string): string{ // 模拟操作 return key + name }
4.可索引接口
-
可索引接口:对数组、对象的约束(不常用)
-
数组的约束
interface UserArr{ [index:number]:string } let arr:UserArr = ['lixing']
-
对象的约束
interface UserArr{ [index:string]:any } let arr:UserArr = { name: '张三', age: 23 }
5.类类型接口
-
类类型接口:对类的约束 和 抽象类比较相似
interface Animal{ name:string; eat(str:string):void } class Dog implements Animal{ name:string; constructor(name:string){ this.name = name } eat(){ console.log('小黑吃粮食!'); } } let p = new Dog('小黑'); p.eat();
6.接口扩展 接口可继承接口
interface Animal{
eat(foot:string):string;
}
interface Web extends Animal{
work():void;
}
class Person implements Web{
public name:string;
constructor(name:string){
this.name = name
}
eat(foot:string){
return `${this.name}吃${foot}`
}
work(){
console.log(`${this.name}敲代码`);
}
}
let p = new Person('小林');
console.log(p.eat('粮食'));
p.work()
十四、TypeScript 中的泛型
1.泛型的概念:
- 软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
- 在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类的数据。这样用户就可以以自己的数据类型来使用组件。
- 通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持。
2.泛型函数
// 泛型:可以支持不特定的数据类型 要求:传入的参数和返回的的参数一致
// T表示泛型,具体什么类型是调用这个方法的时候决定的
function getData<T>(value:T):T{
return value;
}
getData<number>(123)
function getData<T>(value:T):any{
return value;
}
getData<number>(123)
3.泛型类
-
泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串你两种类型。通过类的泛型来实现
class MinClass<T> { public list: T[] = []; add(num: T): T[]{ this.list.push(num) return this.list } minNum():T{ let min = this.list[0]; for (let i = 0; i < this.list.length; i++) { const element = this.list[i]; if (min > element) { min = element } } return min } } let person = new MinClass<string>(); // 实例化类,并且证明类的泛型是number console.log(person.add('a')); console.log(person.add('c')); console.log(person.add('e')); console.log(person.minNum());
4.泛型接口
-
// 泛型接口 interface ConfigFn{ <T>(value:T):T; } let getData:ConfigFn = function<T>(value:T):T{ return value; } getData<string>('张三')
-
// 泛型接口 interface ConfigFn<T>{ (value:T):T; } function getData<T>(value:T):T{ return value; } let myGetData:ConfigFn<string> = getData; myGetData('张三');
十五、TypeScript 泛型类 把类作为参数类型的泛型类
// 操作数据库的泛型类
calss MysqlDb<T>{
add(info:T):boolean{
console.log(info);
return true
}
}
//1、定义一个User类和数据库进行映射
class User{
username:string | undefined;
pasword:string | undefined;
}
var u = new User();
u.username = '张三';
u.password = '123456';
var Db = new MysqlDb<User>();
Db.add(u)
1.统一封装 Mysql、Mssql、mongodb
- 功能:定义一个操作数据库的库 支持 Mysql Mssql MongoDb
- 要求:Mysql Mssql MongoDb 功能一样 都有 add update delete get方法
- 注意:约束统一的规范、以及代码重用
- 解决方案:需要约束规范所以要定义接口,需要代码重用所以用到泛型
- 接口:在面向对象的编程中,接口时一种规范的定义,它定义了行为和动作的归覅能否
- 泛型 通俗理解:泛型就是解决 类 接口 方法的复用性。
interface DBI<T>{
add(info:T):boolean;
update(info:T,di:number):boolean;
delete(id:number):boolean;
get(id:number):any[];
}
// 定义一个操作mysql数据库的类 注意:要实现泛型接口 这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T>{
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, di: number): boolean {
throw new Error("Method not implemented.");
}
delete(id: number): boolean {
throw new Error("Method not implemented.");
}
get(id: number): any[] {
throw new Error("Method not implemented.");
}
}
class User{
userName: string | undefined;
password: string | undefined;
}
let person = new User();
person.userName = 'linxing';
person.password = '123456'
let OMysqlDb = new MysqlDb<User>()
OMysqlDb.add(person);
十六、TypeScript中的装饰器
1.什么叫装饰器?
- 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或传参上,可以修改类的行为。
- 通俗的讲 装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
- 常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
- 装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
- 装饰器是过去几年中 JS 最大的成就之一,已是 es7 的标准特性之一
2.装饰器的类别
-
类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。传入一个参数
-
普通装饰器(没有参数)
function logclass(parms:any){ parms.prototype.sayName = function () { console.log(this.name); } } @logclass class Web { public name:string; constructor(name:string){ this.name = name } } let person:any = new Web('linxing'); console.log(person); person.sayName();
-
装饰器工厂(带参)
// 装饰器 function logclass(params:string){ return function(target:any){ q target.prototype.apiUrl = params; } } @logclass('http://www.itying.com/api') class Web { constructor(){} } let person:any = new Web(); console.log(person.apiUrl);
-
类装饰器重载 类的构造函数
// 装饰器 function logclass(target:any){ console.log(target); return class extends target{ apiUlr:any = '我是修改过后的数据'; getData(){ console.log(this.apiUlr); } } } @logclass class Web { public apiUlr: string | undefined; constructor(){ this.apiUlr = '我是构造函数里的apiurl' } getData(){} } let person:any = new Web(); console.log(person.apiUlr);
-
属性装饰器
- 属性装饰器表达式会在运动时当作函数被调用,传入下列2个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的对象
- 成员的名字