TypeScript基础

1. TypeScript介绍

1.1 TypeScript是什么

TypeScript简称TS,是JavaScript的超集,JS有的TS都有。

TypeScript等于Type加JavaScript,在JS的基础上,为JS添加了类型支持。

TypeScript是微软开发的开源编程语言,可以在任何运行JavaScript的地方运行。

//TypeScript 代码: 有明确的类型,即number(数值类型)
let age1:number = 18
//JavaScript 代码: 无明确类型
let age2 = 18

1.2 TypeScript为什么要为JS添加类型支持

背景:JS的类型系统存在”先天缺陷“,JS代码中绝大部分都是类型错误(Uncaught TypeError)。

问题:增加了找BUG、改BUG的事件,严重影响开发效率。

从变成语言的动静来区分,TypeScript属于静态类型的编程语言,JS属于动态类型的编程语言。

静态类型:编译期做类型检查;动态类型:执行期做类型检查。

代码编译和代码的执行顺序:1.编译 2.执行

对于JS来说:需要等到代码真正去执行的时候才能发现错误(晚)

对于TS来说:在代码编译的时候(代码执行前)就可以发现错误(早)

并且,配合VSCode等开发工具,TS可以提前到在编写代码的同时就发现代码中的错误,减少找BUG,改BUG的时间。

1.3 TypeScript相比于JS的优势

1.更早(写代码的同时)发现错误,减少找BUG,改BUG的时间,提升开发效率

2.程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验。

3.强大的类型系统提升了代码的维护性,使得重构代码更加容易。

4.支持最新的ECMAScript语法,优先体验最新的语法,让你走在前端技术的最前沿。

5.TS类型推断机制,不需要在代码中的每个地方都显示标注类型,让你在享受优势的同时,尽量的降低了成本。

除此之外,VUE3源码使用TS重写,Angular支持TS,React与TS完美配合,TypeScript已经成为大中型前端项目的首先编程语言

2. TypeScript初体验

2.1 安装编译TS的工具包

Node.JS和浏览器,只认识JS代码,不认识TS代码,需要先将TS代码转换为JS代码,然后才能运行。

安装命令:npm i -g typescript

typescript包:用来编译TS代码的包,提供了tsc命令,实现了TS->JS的转化

验证是否安装成功:tsc -v(查看typescript版本)

在这里插入图片描述
在这里插入图片描述

2.2 编译并运行TS代码

1.创建hello.ts文件(注意:TS文件的后缀名为.ts)

2.将TS编译为JS:在终端中输入命令,tsc hello.ts(此时,在同级目录中会出现一个同名的JS文件)

3.执行JS代码:在终端中输入命令,node hello.js。

在这里插入图片描述

所有合法的JS代码都是TS代码,由TS编译生成的JS文件,代码中就没有类型信息了。

console.log('Hello TS');
let age:number = 18
console.log(age);

2.3 简化运行TS的步骤

问题描述:每次修改代码后,都要重复执行两个命令,才能运行TS代码,太繁琐。

简化方式:使用ts-node包,直接在Node.js中执行TS代码。

安装命令:npm i -g ts-node(ts-node包提供了ts-node命令)

使用方式:ts-node hello.ts

解释:ts-node命令在内部偷偷的将TS->JS,然后,再运行JS代码

2.4 TypeScript常用类型

TypeScript是JavaScript的超集,TS提供了JS的所有功能,并且额外增加了:类型系统

  • 所有的JS代码都是TS代码
  • JS有类型(比如:number/string),但是JS不会检查变量的类型是否发生变化。而TS会检查。

TypeScript的类型系统的主要优势:可以标记出代码中的意外行为,从而降低了发生错误的可能性。

1.类型注解

2.常用基础类型

3. TypeScript常用类型

3.1 类型注解

示例代码:

let age:number = 18;

说明代码中的 :number 就是类型注解。

作用:为变量添加类型约束。比如上述代码中,约定变量age的类型为number(数值类型)。

解释:约定了什么类型,就只能给变量赋值该类型的值,否则就会报错

在这里插入图片描述

3.2 常用基础类型概述

可以将TS中的常用基础类型细分为两类:1.JS已有类型 2.TS新增类型

1. JS已有类型

  • 原始类型:number/string/boolean/null/undefined/symbol
  • 对象类型:object(包括:数组,对象,函数等对象)

2. TS新增类型

  • 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any等

3.3 原始类型

1.原始类型:number/string/boolean/null/undefined/symbol。

特点:简单。这些类型,完全按照JS中类型的名称来书写

let age:number = 8; //number
let MyName:string = '智健'; //string
let isLoading:boolean = false; //boolean
let a:null = null; //null
let b:undefined = undefined; //undefined
let s:symbol= Symbol(); //symbol

3.4 数组类型

2.对象类型:object(包括,数组,对象,函数等对象)。

特点:对象类型,再TS中更加细化,每个具体的对象都有自己的语法类型。

  • 数组类型的两种写法:(推荐使用number[]写法)
let numbers:number[] = [1,2,3];
let strings:Array<string> = ['a','b','c'];

需求:数组中既有number类型,又有string类型

let arr:(number|string)[] = [1,'a',2,'b'];

解释:|(竖线)在TS中叫做联合类型(由两个或多个其他类型组成的类型,表示可以是其中的任意一种类型)。

注意:这是TS中联合类型的语法,只有一根竖线,不要与JS中的或(||)混淆了。

3.5 类型别名

类型别名(自定义类型):为任意类型起别名。

使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用

type CustomArry = (number|string)[];
let arr1:CustomArry = [1,'a','b',2]
let arr2:CustomArry = [1,6,'b',2]

解释:

  1. 使用type关键字创建类型别名。
  2. 类型别名(比如此处的CustomArry),可以是任意合法的变量名称
  3. 创建类型别名后,直接使用该类型别名作为变量类型注解即可。

3.6 函数类型

函数的类型实际上指的是:函数参数和返回值的类型

为函数指定类型的两种方式:1.单独指定参数、返回值类型 2.同时指定指定参数、返回值类型

1.单独指定参数、返回值类型

//方式一
function add1(num1:number,num2:number):number{
    return num1 + num2;
}
//方式二
const add2 = (num1:number,num2:number):number=>{
    return num1 + num2;
}

2.同时指定指定参数、返回值类型

const add: (num1:number,num2:number) => number = (num1,num2) =>{
    return num1 + num2;
} 

解释:当函数作为表达式时,可以通过类似于箭头函数形式的语法来为函数添加类型。

注意:这种类型只适用于函数表达式。

如果函数没有返回值,那么,函数的返回值类型为:void

function greet(name : string) : void{
    console.log('Hello' , name);
}

使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数了比如,数组的slice 方法,可以slice() 也可以slice(1) 还可以slice(1,3)。

function mySlice(start?: number,end?: number) : void{
    console.log('起始索引:',start,'结束索引:',end);
}

可选参数:在可传可不传的参数名称后面添加?(问号)注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数。

3.7对象类型

JS中的对象是由属性和方法构成的,而T5 中对象的类型就是在描述对象的结构(有什么类型的属性和方法对象类型的写法:

let person1 : { name : string ; age : number ; sayHi(): void } = {
    name : '李睿' , 
    age : 23 , 
    sayHi(){}
}

let person2 : { 
    name : string 
    age : number 
    sayHi(): void } = {
    name : '李睿' , 
    age : 23 , 
    sayHi(){}
}

let person3 : { 
    name : string 
    age : number 
    sayHi:() => void } = {
    name : '李睿' , 
    age : 23 , 
    sayHi(){}
}

解释:

  1. 直接使用什来描述对象结构。属性采用属性名: 类型的形式,方法采用方法名(): 返回值类型的形式。
  2. 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如: greet(name:string): void)。
  3. 在一行代码中指定对象的多个属性类型时,使用;(分号)来分隔。
  • 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉;(分号)。
  • 方法的类型也可以使用箭头函数形式 (比如:{sayHi:()=> void })。

对象的属性或方法,也可以是可选的,此时就用到可选属性了比如,我们在使用 axios(f…) 时,如果发送GET 请求,method 属性就可以省略。

function myAxios(config :{url:string;method?:string}){
    console.log(config);
}

可选属性的语法与函数可选参数的语法一致,都使用?(问号)来表示。

3.8接口

3.8.1使用接口

当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。

//声明接口
interface IPerson{
    name: string 
    age : number
    sayHi():void
}
//使用
let person : IPerson={
    name:'李睿',
    age: 23,
    sayHi(){}
}

解释:

  1. 使用interface关键字来声明接口。
  2. 接口名称(比如,此处的IPerson),可以时任意合法的变量名称。
  3. 声明接口后,直接使用接口名称作为变量的类型。
  4. 因为每一行只有一个属性类型,因此,属性类型后没有;(分号)

3.8.2接口与类型别名的对比

interface(接口)和type(类型别名)的对比

1.相同点:

  • 都可以给对象指定类型

2.不同点

  • 接口,只能为对象指定类型
  • 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名
//接口
interface IPerson{
    name: string 
    age : number
    sayHi():void
}
//类型别名
type IPerson{
    name: string 
    age : number
    sayHi():void
}
    
type NumStr = number|string

3.8.4接口继承

如果两个接口之间有相同的属性或者方法,可以将公共的属性或方法抽离出来,通过继承 来实现复用。

比如,这两个接口都有x,y两个属性,重复写两次,可以,但是很繁琐。

interface Point2D {x:number; y:number}
interface Point3D {x:number; y:number; z:number}

let p2 : Point2D = {
    x:1,
    y:2
}
let p3 : Point3D = {
    x:1,
    y:2,
    z:3
}

更好的方式:

interface Point2D{x:number;y:number}
interface Point3D extends Point2D {z:number}

let p2 : Point2D = {
    x:1,
    y:2
}
let p3 : Point3D = {
    x:1,
    y:2,
    z:3
}

解释:

  1. 使用extends(继承)关键字实现了接口Point3D继承Point2D
  2. 继承后,Point3D就有了Point2D的所有属性和方法(此时,Point3D同时有x,y,z三个属性)

3.9元组

场景:可以在地图,使用经纬度坐标来标记位置信息。

可以使用数组记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型

let position : number[] = [23.587,226.6578]

使用number[]的缺点:不严谨,因为该类型的数组中可以出现任意多个数字

更好的方式:元组(Tuple)。

元组类型时另一种类型的数组,它确切地知道包含多少个元素,以及每个元素的类型。

let position : [number,number] = [23.587,226.6578]

解释:

  1. 元组类型可以确切地标出有多少个元素,以及每个元素的类型。
  2. 该示例中,元素有两个元素,每个元素的类型都是number。

3.10类型推论

在TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型。

换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!

发生类型推论的2种常见场景:1 声明变量并初始化时 2决定函数返回值时。

在这里插入图片描述
在这里插入图片描述

注意:这两种情况下,类型注解可以省略不写!

推荐:能省略类型注解的地方就省略 (偷懒,充分利用TS类型推论的能力,提升开发效率)!

技巧:如果不知道类型,可以通过鼠标放在变量名称上,利用VSCode 的提示来查看类型。

3.11类型断言

有时候你会比TS更加明确一个值的类型,此时,可以使用类型断言来指定更具体地类型

<a href="https://www.baidu.com/" id="link">百度一下</a>
const aLink: document.getElementById('link')

注意:getElementByld方法返回值的类型是HTMLElement,该类型只包含所有标签公共的属性或方法,不包含a标签特有的 href 等属性。

因此,这个类型太宽泛(不具体),无法操作 href等 a 标签特有的属性或方法。

解决方式:这种情况下就需要使用类型断言指定更加具体的类型。

使用类型断言:

const aLink: document.getElementById('link') as HTMLAnchorElement

解释:

  1. 使用as 关键字实现类型断言。
  2. 关键字as后面的类型是一个更加具体的类型(HTMLAnchorElement是 HTMLElement 的子类型)。
  3. 通过类型断言,aLink 的类型变得更加具体,这样就可以访问 a 标签特有的属性或方法了。

另一种语法,使用 <> 语法,这种语法形式不常用知道即可:

const aLink: <HTMLAnchorElement>document.getElementById('link')

技巧:在浏览器控制台,通过console.dir()打印 DOM 元素,在属性列表的最后面,即可看到该元素的类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java-小小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值