素材巴巴 > 程序开发 >

TypeScript的整理归纳

程序开发 2023-09-03 20:45:51

JavaScript的特点

强类型和弱类型

强类型语言和弱类型语言的区别

强类型:强类型的变量一经声明,就只能存储这种类型的值,其他的值则必须通过转换之后才能付给该变量,有编译器自动理解的转换,也有由程序员明确指定的强制转换,代表的就是Java、C++等等

弱类型:弱类型的变量类型则是随着需要不断转换,弱类型一般数据类型是根据值来确定的。Java、PHP

JS的问题

JS早期设计出来的目的就是简单快速的解决网页动态交互的效果。当初在设计过程中就要求,简单、容易上手,并且开发快速。所以早期的JS设计为弱类型、甚至模块化都没有。

随着JS语言的发展,目前前端工程非常的庞大,就导致了一些列问题。变量类型没有约束,导致在开发过程中很多问题都无法检测到,允许过程中才会抛出一些异常。并且JS这门语言是无需编译的,直接允许在浏览器里面,那就意味着,错误都在运行过程中出现的。

案列1:运行过程中才检测到对象没有某个属性

const object = {name:"xiaowang"
 }
 console.log(object.eat());
 

案列2:函数的参数类型不确定

function add(num1,num2){return num1 + num2
 }
 add("xiaowang",10)
 

当我们要累加两个数字时,你可以传递任何数据类型

案列3:参数传递不对,直接报错

function list(arr){return arr.reduce((sum,next)=>{return sum+=next},0)
 }
 const res = list([1,2,3,4,5]) //假设不传递数组,代码也不会报错,运行报错
 

案列4:有些代码运行的时候才会检测到问题

setTimeout(()=>{},1000)
 

强类型的好处

  1. 代码在编译的过程中,就会抛出一场,那就意味着,我们在编译的时候就可以解决很多问题,而不用上线后在检查各种错误。

  2. 编码的过程中,只能提示更加的准确,比如函数的参数,参数类型等等。

    function show(obj){obj.name
     }
     

    在使用obj的时候,你是没有提示的,因为编译器不知道obj的什么类型。

  3. 减少不必要的类型判断,你为了保证参数的类型是你想要的类型,你要自己编写一些类型判断的代码

    function show(num1,num2){if(typeof num1 && typeof num2){}
     }
     

Typescript介绍

  1. TypeScript 是由微软开发的一款开源的编程语言。

  2. TypeScript 是 Javascript 的超集,遵循最新的 ES6、ES5 规范。TypeScript 扩展了 JavaScript

的语法。

  1. TypeScript 更像后端 java、C#这样的面向对象语言,可以让 js 开发大型企业项目。

  2. 谷歌也在大力支持 Typescript 的推广,谷歌的 angular2.x+就是基于 Typescript 语法。

  3. 最新的 Vue 、React 也可以集成 TypeScript。

  4. Nodejs 框架 Nestjs、midway 中用的就是 TypeScript 语法。

TypeScript安装

在使用 npm 命令之前电脑必须得安装 nodejs

npm install -g typescript 
 cnpm install -g typescript 
 

下载成功后的结果:

image-20210420233429445

测试结果

tsc -v
 

TypeScript配置

基础编译

创建项目TS01-environment,创建index.ts文件

var username:string = "xiaofei";
 

将代码编译为js,终端执行

tsc index.ts
 

默认会在项目同级目录下面产生js文件

tsconfig.json配置

你可以创建tsconfig.json配置文件,设置编译后产生的文件路径

  1. 在项目的根目录下面执行

    tsc --init
     
  2. 修改配置文件,设置默认编译目录,添加js目录

    "outDir": "./js",  
     
  3. 老版本 vscode 点击: 任务->运行任务-> tsc:监视-tsconfig.json 然后就可以自动生

    成代码了

    最新版本 vscode 点击: 终端->运行任务->typescript->tsc:监视-tsconfig.json 然后就

    可以自动生成代码了

    接下来在开发的时候,就可以自动完成编译功能。

TypeScript数据类型

数字类型

let price:number = 100;
 //一旦申明了数据类型,就无法赋值其他类型的值
 price = true; //报错
 

整数型和浮点数都可以使用number类型来表示

布尔类型

let flag:boolean = true;
 flag = false;
 console.log(flag);
 

字符串类型

let username:string = "xiaowang"
 username = "xiaofei";
 

数组类型

  1. 第一种定义数组的方式

    // 定义数组的第一种方式,值必须全为number类型
     let covers:number[] = [10,20,30];
     console.log(covers);
     
  2. 第二种定义数组的方式

    // 定义数组的第二种方式。
     let covers2:Array = ["xiaowang","xiaozhang"]
     console.log(covers2);
     
  3. 第三种定义数组的方式

    // 定义数组的第三种方式
     let covers3:any = [1,"xiaowang",true]
     console.log(covers3);
     

元组类型(tuple)

元组类型(tuple)属于数组的一种,元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string和number类型的元组

let points:[string,number,boolean] = ["xiaowang",123,true];
 console.log(points);
 

枚举类型

enum类型是对JavaScript标准数据类型的一个补充,比如:支付成功后的状态 0:失败 1:超时 2:成功,如果我们在代码中 使用0 1 2表示就不清除。这个时候可以用枚举类型

enum state {error=0,timeout=1,success=2};
 let result = state.success;
 let result2 = state.timeout
 console.log(result);
 console.log(result2);const order = {id:"001",date:"2021-09-01",state:state.error
 }
 

any任意类型

你可以给变量设置any类型,那变量就可以支持任何的数据类型

let num:any;
 num = 10;
 num = "xiaowang"
 

有时候我们不知道设置什么类型的时候,可以指定any类型

const obox:any = document.getElementById("box")
 obox.style.backgroundColor = "res";
 

document.getElementById(“box”)获取到的是节点类型,这个时候用数据类型不好表示,就用any类型

undefined和null

let male:number | undefined;
 // 没有赋值输出undefined
 console.log(male);
 // 赋值后输出number
 male = 20;
 console.log(male);
 

当一个变量定义后没有赋值,那默认类型为undefined。使用|表示数据类型可以选择。

void类型

表示一个函数没有任何的返回类型。如果函数指定了某一个返回类型,那就必须返回指定的格式

function show():void{console.log(123);
 }
 show()
 

在ts里面严格要求,函数没有返回值的时候,你需要定义void。类似于在java中

public void show(){}
 

你可以指定返回值类型,返回的数据类型必须匹配

function computed():number{return 123;
 }
 

never类型

never类型表示的是那些永不存在的值的类型。

例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型;

变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

let others:never;
 others=(()=>{throw new Error("错误")
 })();
 

object类型

在TS中object类型主要用于表达{}、[]、function这三种类型。

let user:object = {}
 let user2:object = []
 let user3:object = function(){}
 

如果你指定要一个对象类型,那可以使用一下的表达方式

let user4:{name:string} = {name:"xiaowang"}
 

前面声明的数据类型要必须和后面的数据类型保持一致。

TypeScript函数

函数返回值

在ES5中我们定义函数的语法为

//函数定义
 function show(){return 123;
 }
 //函数表达式
 const computed = function(){return 123
 }
 

在TS中定义函数,和之前相对需要定义返回类型

function show():number{return 123;
 }const show2 = function():string{return "xiaowang";
 }
 

参数类型

在TS中函数形参必须指定对应的数据类型,否则编译会报错

function exec(username:string,password:number):string{return `${username}+${password}`;
 }
 

一旦指定了参数的数据类型,调用函数必须传递参数,并且是指定的数据类型

exec("xiaofang",20)
 

当然TS也可以支持可选参数

function exec2(username:string,password?:number):string{return `${username}+${password}`;
 }
 

在参数后面加上?表示这个参数为可选参数,那样可以默认不传递,值默认undefined

exec2("xiaofang")
 

默认参数配置,参数由默认值就可以不传递值

function getInfo(age:number = 10):void{console.log(`age`, age)
 }
 getInfo(20);
 

剩余参数

function getInfo2(a:number,...args:number[]){console.log(a);console.log(args);
 }
 getInfo2(1,2,3,4,5);
 

剩余参数会自动将2,3,4,5封装到args数组中。编译为js代码的时候会使用arguments来进行数据封装。

函数重载

在JAVA中,方法的重载代表,方法名字相同,函数的参数类型,和参数个数不一致。

主要的作用就是通过不同的参数来执行不同的业务逻辑。

在TS中我们也有重载,但是和JAVA的重载有些区别

function getUserInfo(name:string):string;
 function getUserInfo(name:number):number;
 function getUserInfo(name:any):any{if(typeof name == "string"){return "xiaowang"}else{return 123;}
 }
 getUserInfo(123);
 

TypeScript类定义

类定义

class People{username:string;constructor(name:string){this.username = name;}show():void{console.log("我的名字为:",this.username);}
 }const peo = new People("xiaowang");
 peo.show();
 

上面定义类的语法和ES6的语法一样,只是在数据类型上增加了约束。

类继承

class Police extends People2{constructor(name:string){super(name);}work(){console.log(this.username+"正在工作");}
 }
 const police  = new Police("刘杰");
 police.work();
 

子类继承父类和ES6的语法也是相差无几。

类修饰符

在TS中新增了访问修饰符,对属性进行修饰,可以指定属性在不同场景下的使用情况

访问修饰含义范围private私有类型本类protected受保护类型本类、子类public公有类型本类、子类、外部

public :如果你没有写类型,那系统默认定义为public

class People3{public username:string;constructor(name:string){this.username = name;}show():void{console.log("我的名字为:",this.username);}
 }
 let peo3 = new People3("xiaowang");
 console.log(peo3.username);

protected:特点:类的外面、本类和子类都可以访问username,这就是public的范围

protected username:string;
 

一旦把username类型变成protected,那外部使用编译报错

let peo3 = new People3("xiaowang");
 console.log(peo3.username); //编译报错
 

private:一旦换成private来修饰属性,那属性就无法直接被外部访问。可以利用这种特性来对属性进行封装。

class People3{private username:string;constructor(name:string){this.username = name;}getUsername(){return this.username}setUsername(name:string){this.username = name;}show():void{console.log("我的名字为:",this.username);}
 }
 

私有属性,提供get和set方法类对数据进行修改,达到封装的目的。

类只读属性

类的属性你可以设置为只读

class People{username:string;public readonly age:number = 10constructor(name:string){this.username = name;}show():void{console.log("我的名字为:",this.username);}
 }
 const peo = new People("xiaowang");
 peo.age =20; //报错
 

静态定义

在开发中我们经常会使用到静态方法或者静态变量。比如工具包的封装,好处就是不用创建实例就可以使用这些方法和属性,可以节约内存空间,接下来我们就看一下TS中的静态方法和静态属性

class Student{static username:string="xiaowang";constructor(){}static show():void{console.log(this.username);}
 }console.log(Student.username);
 Student.show();

静态方法和静态函数都要通过类来进行调用。

不能通过实例对象来调用静态属性和静态行为。

也不能在实例行为里面调用静态方法或者属性

多态

多态是面向对象的一个重要特点,表示一个对象的不同形态。多态其实就是继承的一种表现行为。必须要在继承环境中才能有多态

父类对象定义了一个方法,每个子类对象都对其进行了实现。这个结果就是多台表现

抽象类

TypeScript中提供了一种抽象类,他用于给其他类提供基类。不能被实例化

abstract class Car{abstract run():any;stop(){}
 }const car = new Car(); //不能实例化
 

抽象类中中可以有抽象方法,也可以有普通方法,但是一个类中有抽象方法,这个类必须是是抽象类。

抽象类主要是定义了父类的规范。

子类实现:子类继承了抽象父类,那就必须要抽象方法

class Polo extends Car{run(){}
 }
 

接口

在面向对象的编程中,接口是一种编程规范,他定义了行为和动作的规范,在程序设计中,接口起到了限制和规范的作用。接口定义了某一批类需要遵循的规范,接口不关系这些类的内部状态,也不关系这些类的具体实现细节,他只规定了这批类里面提供哪些方案。

TypeScript的接口和Java类似,同时还增加了更加灵活的接口类型,包括属性、函数、可索引和类等等。

接口类型:

  1. 属性类型接口
  2. 函数类型接口
  3. 可索引接口
  4. 类类型接口
  5. 接口扩展
属性类型接口
interface IUser {username:stringpassword:number,age?:number
 }
 let user2:{username:string} = {username:"xiaowang"}
 let user:IUser = {username:"xiaowang",password:123
 }
 

我们在定义一个对象的时候,可以将对象需要的属性明确规定下来。这样在操作对象的时候就必须要匹配到这个属性和值的变化。

函数类型接口

对于函数来说,我们传递参数的方式

function show(name:string){console.log(name)
 }
 show("xiaowang");
 

对参数进行规范

/*** * @param username 传递参数必须传递一个对象*/
 function show(username:{firstName:string}){}
 //假设传递的属性不为firstName编译报错
 show({firstName:"xiaozhang"});
 

如果还有其他函数也需要这种规范,我们还需要重复写一次,所以为了开发方便,我们可以将这种约束提取出来。

对函数参数进行统一规范,这个时候我们就需要用到interface来定义接口

interface userType{firstName:string,lastName:string
 }function check(user:userType){console.log(user.firstName);console.log(user.lastName);
 }
 check({firstName:"xu",lastName:"chaobo"})
 

如果将参数提取出来,单独放在外面定义,我们可以在对象里包含其他属性

const obj = {firstName:"xu",lastName:"chaobo",age:10
 }
 check(obj);
 

可选参数

lastName?:string
 

在属性里面增加一个?:代表这个参数是可选参数。

案例:

interface 
 
函数类型接口

函数类型的接口,可以对函数参数以及函数的返回值进行约束

interface login{(username:string,password:string):string
 }const wxLogin:login = function(username:string,password:string):string{return username+password;
 }const accountLogin:login = function(username:string,password:string):string{return username+password+"key1"
 }
 
可索引接口(少)

可索引接口主要是对数组、对象的约束。

interface arrinter{//默认值,代表下标[index:number]:string
 }const array:arrinter = ["xiaowang","xiaozhang"]
 
类类型接口

对类进行规范,可以在接口中定义行为,子类来实现这个行为

interface AnimalInter{eat(name:string):void;play():void;
 }class Dog implements AnimalInter{eat(){console.log();}play(){}
 }
 

可以对接口进行多实现

interface Phone{call(name:string):void;play():void;
 }
 interface Psp{playGame():void;
 }
 class IPhone implements Phone,Psp{call(){console.log();}play(){}playGame(){}
 }
 

接口还可以继承接口。子类实现的时候,必须实现所有的方法。

TypeScript泛型

我们在开发中要创建组件来达到复用,组件不仅要支持当前传递的数据类型,同时还能对数据类型进行扩展。这样在项目中就可以根据不同类型的值来进行业务处理

泛型就是解决了类、接口、方法的重用性。

函数泛型

我们要定义一个函数,函数需要返回不同类型的数据

/*** 定义一个函数,需要返回不同类型的值* 要返回不同类型的值,只能创建多个函数*/
 function show(value:number):string{return "xiaowang"
 }
 

使用泛型来进行开发

function check(value:T):T{return value;
 }
 check("123");
 

案列:编写一个函数,接受一个数组,返回数组中最大值

function compare(arr: number[]): number {let max = arr[0]arr.forEach(item => max = item > max ? item : max)return max;
 }
 

我们编写了一个函数,接受一个数组,返回数组中的最大值,但是如果我要比较字符串,传递进来的数组存放的是字符串,那就无法中重用这个代码

function compare2(arr:T[]):T{let max = arr[0]arr.forEach(item => max = item > max ? item : max)return max;

一般在开发中使用T来代表默认的数据类型。

类的泛型

/*** 类的泛型*/
 class compValue{// 初始化一个数组public list:T[] = [];add(num:T):void{this.list.push(num)}min():T{let comp = this.list[0];for(let i=0;ithis.list[i]){comp = this.list[i]}}return comp;}
 }const comp = new compValue();
 comp.add(20)
 comp.add(22)
 comp.add(24)
 comp.add(19)
 console.log(comp.min());const comp2 = new compValue();
 comp2.add("a")
 comp2.add("b")
 comp2.add("c")
 comp2.add("d")
 console.log(comp2.min());

给类定义了泛型,可以根据不同的类型来执行不同的结果。

接口泛型

interface params{(value:T):T
 }function show(value:T):T{return value;
 }show(123)
 show("xiaowang")
 

TypeScript模块

从ECMAScript 2015开始,JavaScript引入了模块的概念。TypeScript也沿用这个概念。

模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用 import形式之一。


 

命名空间

在TS开发中,我们经常会遇到类名重复,或者接口名字重复的问题,这个时候为了区分这些名字。我们可以给自己的类加上一个命名空间


 

React中使用TS

在create-react-app的官方文档中,我们可以找到创建TS版本的项目

地址为:https://create-react-app.bootcss.com/docs/getting-started

家人们关注下哇!!!爱你们哦


标签:

上一篇: 用 MongoDB Express NodeJS 搭建博客 下一篇:
素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。