TypeScript基础

TypeScript是JavaScript的一个超集,任何合法的JavaScript代码都能在TypeScript中运行,它给原生的JavaScript带来了强类型的定义,需要注意的是TypeScript无法在浏览器中运行。

TypeScript可以规范我们的代码,让我们能够在代码的编译阶段就能及时发现错误,它只是在原生js的基础上加上了一层类型定义

使用TypeScript的好处

  • 自动进行类型检查
  • 避免出现低级错误
  • 节约重复的劳动,解放劳动力
  • 帮助我们写出质量更高的代码

1、TypeScript基础

1.1 基础类型

boolean、string、number、array、tuple、enum、null、undefined、object、void、never、any、unknown

当我们为变量指定了类型以后,只允许给变量赋予对类型的值,不然就编译报错

在这里插入图片描述

1.1.1 Array

TypeScript中声明array的写法

let list1:number[] = [1,2,3]
let list2: Array<number> = [1,2,3]
let list3 =[1,2,3]

这三个数组都只允许写入number类型,当我们声明变量切未指定类型的时候,数组的类型会自动根据你初始化的类型来定义数组类型

也可以给变量指定多个类型

let list1:(number | string) = [1,2,'dean']
let list2:Array<number | string> = [1,2,'dean']
let list3 = [1,2,'dean']

1.1.2 Tupple 元组类型

即元组类型,元组是一个固定长度,固定类型的数组,声明一个元组的时候一定指明它的类型

在这里插入图片描述

改变长度,改变类型都会让程序报错

但是这个类型存在一个bug,当我们使用push方法的时候程序不会报错 且能正常运行

let personal:[number,string] = [1,'dean']
personal.push(3)
console.log(personal)  //正常输出[ 1, 'dean', 3 ]

1.1.3 any

any类型其实就是原生js声明的数据类型,即该变量没有指定类型

1.1.4 unknown 类型

unknown 类型 和 any类型有点相似,都是没有定义变量的类型,unknown跟any的最大的不同是,unknown不保证类型,但是能保证类型的安全

//any类型
let val1:any = 666
val1 = true
val1 = 'asfsdf'
val1 = {}
val1()
val1.toUpperCase()

以上的代码,在编译时并不会报错,但是在运行时会报错

//unknown类型
let val1:unknown= 666
val1 = true
val1 = 'asfsdf'
val1 = {}
val1()
val1.toUpperCase()

在这里插入图片描述

而把类型定义成unknown的时候 在编译时就会报错,我们在使用unknown变量的时候需要做一定程度的判断或者类型转换,只有了确定了变量类型以后才能正常使用功能对应的函数。

在这里插入图片描述

1.1.5 enum 枚举类型

enum Color {
	red,
	grenn,
	blue
}

let color = Color.blue  //2

我们也可以指定数据

enum Color {
	red='#FF0000',
	grenn='#00FF00',
	blue='#0000FF'
}

let color = Color.blue // #0000FF

1.1.6 void

一个函数在没有任何返回的情况下,这个函数就是一个void类型;

void和undefined都表示没有,但是undefined指的是变量没有赋值,没有初始化,而void他所说的是变量本身就不存在

function printRes():void {
	consol.log('dean')
}

console.log("hello",printRes())  //hello undefined

由于函数printRes是void类型,所以表明他本身就不存在,所以无法打印出函数里面的内容

1.1.7 never

一个函数永远执行不完,就是never类型

function whileLoop(){
	while(true){
		console.log('lalala')
	}
}
//这里的whileLoop函数就是一个never类型

1.2 TypeScript的高级类型

union 联合类型、Nullable可空类型、Literal字面量类型

1.2.1 union 联合类型

联合类型指的是一个变量可以同时支持2个或者2个以上的不同类型,不同类型之间用|来分隔


let un1:string | number | string[]

1.2.2 Literal 字面量类型

字面量类型即明确了取值的类型

let li1: 0 | 1 | 3
let li2: 1 | false | 'dean' | [1,2,3] 

当给字面量类型的变量赋值为预定义之外的值时就会报错

1.3 类型适配(类型断言) Type Assertions

声明一个变量时,没有给他指定具体的类型或没有初始化赋值,那他的类型默认就是any,后面再给他赋值,不会转变它的类型,这时候需要用到类型适配

let message  //此时变量的类型是any
message ="abc"  //虽然给他赋值了  但是此时变量的类型还是没有变化
//方式一
let msg1 = (<string> message)
//方式二
let msg2 = (message as string)

两种方式都可以转换变量的类型

1.4 函数类型

跟es6相比,typescript可以为传入函数的参数指定类型

在这里插入图片描述

如果typescript定义了两个参数,那么必须填写参数中所有的参数,而且类型必须匹配

let log2 = (message:string,code:number) =>{
  console.log(message,code)
}

log2("hi",200)

若是想省略某一些参数,可以使用**?**来表示某些参数的可选性

let log3 = (message:string,code?:number) =>{
  console.log(message,code)
}

log3('hi')//hi undefined

也可以这种参数的默认值

let log2 = (message:string,code:number=1) =>{
  console.log(message,code)
}
log2('hi')  //hi 1

需要注意的是不管是可选参数还是默认参数都需要参数列表的末尾,而且需要从后到前的顺序排列

错误展示

只设置第一个参数为可选值,此时代码报错

2 、TypeScript面向对象

2.1 Object对象类型

object的使用方法与原生的类似,但是不同的点是,在TypeScript当我们调用没有定义的内部变量如下的sex,这时候代码就会报错

在这里插入图片描述

object的内部变量都有对应的固定的类型

在这里插入图片描述

所以与JavaScript不同的是,TypeScript对对象类型的定义不是key to value(键值对),而是key to type (键类型对)

我们也可以选择显式的手动定义对象的类型

const person:{
	firstName:string,
  lastName:string,
  age:number
} = {
  firstName:'dean',
  lastName:'郭',
  age:18
}

2.2 Interface 接口

Interface 可以给参数的对象加以限制

在这里插入图片描述

这时所有非法输入都会报错,错误的代码也不会再执行

2.3 class 类

为了让Interface 接口实现高聚合的作用,可以使用class类的概念来实现,有接触过java的应该比较好理解这个类

interface IPoint{
  x:number;
  y:number;
  drawPoint:() =>void;//由于此函数没有返回值所以用void
  getDistances:(p:IPoint) =>number
}

class Point implements IPoint{
  x:number;
  y:number;
  drawPoint = () =>{
    console.log("x:",this.x,"y:",this.y)
  }
  getDistances=(p: IPoint) => {
    return Math.pow(p.x-this.x,2)+Math.pow(p.y-this.y,2)
  }
}

const point =new Point() //创建实例使用new关键词
point.x = 2;
point.y = 3;
point.drawPoint() // x:2 y:3

这里的类是Point,这边的point是对象,对象就是这个类的实例,故对象也被称为实例instance。这里可以举个例子,狗是一个class,大黄是一个对象,大黄出生的这个过程就是实例化

除了直接给坐标点赋值的这个方法,我们还可以使用构造函数constructor

class Point implements IPoint{
  x:number;
  y:number;

	constructor(x:number,y:number){
		this.x = x;
		this.y = y;
	}
  drawPoint = () =>{
    console.log("x:",this.x,"y:",this.y)
  }
  getDistances=(p: IPoint) => {
    return Math.pow(p.x-this.x,2)+Math.pow(p.y-this.y,2)
  }
}

const point =new Point(2,3) //创建实例使用new关键词
ponint.drawPoint() // x:2 y:3

运用了构造函数的话,我们可以在初始化一个Point的时候就可以同时把坐标参数填充进去了

如果在初始化的时候还不想填入参数的话,可以在构造函数中加一个?,即把参数改成可选项,这时候创建新对象就不需要填入参数了,需要注意的是一个类就只有一个constructor

2.4 Access Modifier 访问修饰符

public 公有 (默认情况下所有的成员变量都是public)

private 私有

可以通过使用访问修饰符,在声明构造函数的同时随便完成成员变量的声明以及初始化。

class Point implements IPoint{
  //x:number;
  //y:number;

	constructor(public x:number,public y:number){
		//this.x = x;
		//this.y = y;
	}
  drawPoint = () =>{
    console.log("x:",this.x,"y:",this.y)
  }
  getDistances=(p: IPoint) => {
    return Math.pow(p.x-this.x,2)+Math.pow(p.y-this.y,2)
  }
}

const point =new Point(2,3) //创建实例使用new关键词
point.drawPoint() // x:2 y:3

这边使用public(公有属性)作为关键词

但是设置变量为公有属性会产生一个问题,即便是已经初始化过后的Point对象,我们还是可以对它的x值和y值进行重新赋值,如

const point =new Point(2,3) //创建实例使用new关键词
point.x = 20
point.y = 30
ponint.drawPoint() // x:20 y:30

这种在对象外部直接访问内部成员变量,甚至重新赋值的操作在实际工作中是不安全的,所以我们希望外界避免直接操作Class内部属性,这时候就需要private。

当我们用private来修饰x和y的时候,我们就无法直接访问内部成员变量了

在这里插入图片描述

需要注意的是,接口中定义的变量也好,方法也好都必须是公开的,所以当我们使用private来修饰x和y,而接口中定义还是公有属性,代码就会报错,所以需要删除公有属性

在某些场景下,还是需要从外部来访问x和y,为了满足这个条件的同时

保证这两个属性具有高度的私有隔离,这个时候就需要借助getter和setter这两个方法

interface IPoint{
  drawPoint:() =>void;//由于此函数没有返回值所以用void
  getDistances:(p:IPoint) =>number
  getX:() =>number
  getY:() =>number
  setX:(value) =>void
  setY:(value) =>void
}

class Point implements IPoint{
  //x:number;
  //y:number;

	constructor(private x:number,private y:number){
		//this.x = x;
		//this.y = y;
	}
  drawPoint = () =>{
    console.log("x:",this.x,"y:",this.y)
  }
  getDistances=(p: IPoint) => {
    return Math.pow(p.getX()-this.x,2)+Math.pow(p.getY()-this.y,2)
  }
  setX = (value:number) =>{
    if(value < 0){
      throw new Error("x的数值不能小于0")
    }
    this.x = value
  }
  setY = (value:number) =>{
    if(value < 0){
      throw new Error("y的数值不能小于0")
    }
    this.y = value
  }
  getX = () =>{
    return this.x
  }
  getY = () =>{
    return this.y
  }
}

const point =new Point(2,3) //创建实例使用new关键词
point.setX(20)
point.setY(30)
point.getX()  //20
point.getY()  //30

当我们用setter方法为x或y赋值一个负数的时候,程序编译时就会抛出对应的错误信息

在这里插入图片描述

这样就可以对输入的数值做一定的筛查,防止引起程序的错误

在typescript中还有一种特定的写法来实现get和set的操作

interface IPoint {
  drawPoint: () => void;//由于此函数没有返回值所以用void
  getDistances: (p:IPoint) => number;
  X:number  
  Y:number
}

class Point implements IPoint {

	constructor(private x:number,private y:number){
	
	};
  drawPoint = () =>{
    console.log("x:",this.x,"y:",this.y)
  };
  getDistances=(p: IPoint) => {
    return Math.pow(p.X-this.x,2)+Math.pow(p.Y-this.y,2)
  };
  set X(value:number) {
    if(value < 0){
      throw new Error("X数值不能小于0")
    }
    this.x = value
  };
  set Y (value:number){
    if(value < 0){
      throw new Error("Y数值不能小于0")
    }
    this.y = value
  };
  get X(){
    return this.x
  };
  get Y(){
    return this.y
  };
}

const point =new Point(2,3) //创建实例使用new关键词
point.X = 20
point.Y = 30
point.X  //20
point.Y  //30

需要注意的点是,用了这个方法以后编译器的版本至少设置为es5以上,指定版本的编译命令为**tsc -t es5 main.ts**

2.5 Module 模块

typescript中的模块的用法跟es6相同,都是通过export导出和通过import导入。

将Point类全部转移到一个新的文件point.ts中去,并且用关键字export导出

在这里插入图片描述

然后使用import {Point} from './point’在调用页面进行引入

2.6 Generics 泛型

在typescript中类型加上箭头括号就是泛型 如:Array<number>

泛型的具体用法如下

在这里插入图片描述

当我们为Array指定类型的时候,输入其他类型程序就会报错

在这里插入图片描述

而当我们把数组的泛型改为any的时候,报错虽然消失,但变量l2的类型也变为了any,那样就失去了强类型的意义

这个时候可以在函数的参数前面增加一个<T>动态类型泛型,用T动态的替换any(大写T是一个约定写法,可以随意选用名称替代)

//写法一
let lastInArray = <T>(arr:Array<T>) =>{
  return arr[arr.length-1]
}
//写法二
//let lastInArray = <T>(arr:T[]) =>{
//  return arr[arr.length-1]
//}
const l1 = lastInArray<number>([1,2,3]) //l1:number
const l2 = lastInArray<string | number>(['a','b','c'])//l2:string | number

在lastInArray后写上泛型的一个好处是有可能出现混合类型的情况,如变量l2,若是此时没有写明<string | number>的话,则程序会判定l2是一个string类型而不是一个混合类型

除了上面的但泛型以外还有多泛型的一种用法

let makeTuple =<T,Y>(x:T,y:Y) => [x,y]

const v1 = makeTuple(1,'one') //v1:(string | number)
const v2 = makeTuple<boolean,number>(true,1)  //v2:(boolean | number)

同时泛型也可以指定默认类型

let makeTuple =<T,Y=number>(x:T,y:Y) => [x,y]

const v1 = makeTuple(1,'one') //v1:(string | number)
const v2 = makeTuple<boolean>(true,1)  //v2:(boolean | number)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值