【TypeScript】TS入门到实战(详解)
第一章 前言
1.1 介绍TypeScript
- TypeScript(简称:TS)是 JavaScript 的超集(JS 有的 TS 都有)。
- 从编程语言的动静来区分,TypeScript 属于静态类型的编程语言,JS 属于动态类型的编程语言。 静态类型:编译器做类型检查; 动态类型:执行期做类型检查。 代码编译和代码执行的顺序:先编译再执行。
- 由于TS,在编译时就开始做类型检查了,所以TS 可以提前到在编写代码的同时就发现代码中的错误,减少找 Bug、改 Bug 时间
1.2 TypeScript相比Js的优势
- 更早(写代码的同时)发现错误,减少找 Bug、改 Bug 时间,提升开发效率。
- 程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验。
- 强大的类型系统提升了代码的可维护性,使得重构代码更加容易。
- 支持最新的 ECMAScript 语法,优先体验最新的语法,让你走在前端技术的最前沿。
- TS 类型推断机制,不需要在代码中的每个地方都显示标注类型,让你在享受优势的同时,尽量降低了成本。
1.3 使用TypeScript的准备工作
- 安装ts 的工具包,原因:(浏览器与node只认识js代码,不认识ts代码,安装ts的工具包目的是将ts转为js)
npm i -g typescript
利用tsc -v查看是否安装成功
tsc -v
使用顺序 :
- 例如:创建 hello.ts 文件(注意:TS 文件的后缀名为 .ts)
- 将 TS 编译为 JS:在终端中输入命令,tsc hello.ts(此时,在同级目录中会出现一个同名的 JS 文件)
- 执行 JS 代码:在终端中输入命令,node hello.js
- 使用 ts-node 包,直接在 Node.js 中执行 ts 代码
npm i -g ts-node - 利用ts-node -v查看是否安装成功
ts-node -v使用顺序:直接ts-node hello.ts
第二章 TypeScript的数据类型
2.1 TypeScript的常用类型
2.1.1 概述
- 可以将 TS 中的常用基础类型细分为两类:JS 已有类型 与 TS 新增类型。
- JS已有数据类型:基本数据类型与引用数据类型
- 基本数据类型:number、string、boolean、null、undefined、symbol
- 引用数据类型:object(包括:数据array、函数function、对象等)
- TS新增类型
- 自定义类型(类型别名)、联合类型、接口、元组、自变量类型、枚举、void、any等等
2.1.2 TS使用JS基本数据类型
2.1.2.1 number
let number: number = 23
2.1.2.2 string
let myName: string = '关注ve'
2.1.3.3 boolean
let isYouth: boolean = true
2.1.2.4 null
let a: null = null
2.1.2.5 undefined
let b: undefined = undefined
2.1.2.6 symbol
let s: symbol = Symbol()
2.1.2.7 总结
-
写法: 变量 :数据类型 = 类型值
-
通过数据类型为变量进行约束,从而只能给变量赋值该类型的值
-
代码中查看数据的数据类型:(鼠标悬浮在查看的变量上)
-
当赋值其他类型是报错,例如
2.1.3 TS使用JS引用数据类型
2.1.3.1 数组(array)
- 写法一:
变量:数据类型[] = ['该数据类型的值1','该数据类型值2'……]——(推荐)
const numbers: number[] = [1,2,4,5] // 该写法是一个纯数字数组数据类型,数组内只包含数字类型
const strs: string[] = ['1','2','3'] // 数组内只包含字符串类型
- 写法二:
变量:Array<数据类型> = ['该数据类型的值1','该数据类型值2'……]
const numbers2: Array<number> = [1,2,4,5]
const strs2: Array<string> = ['1','2','3']
- 解释:针对于以上两种方法,只能定义一个数组,然后数组的值只能是纯规定数据类型的值,数组中不能有其他类型的值
- 需求:如果一个数组中能有number、 string、boolean等多个数据类型在同一个数组中
- 解决:联合数据类型:
变量: (数据类型)[] = [字面量,……](后续会对该类型具体解释)
const arr: (number | string | null | boolean)[] = [1,'a',false, null]
// 该写法将|理解成或者,表示arr变量是一个数组,数组里面的值可以有数据类型、字符串类型、null、boolean
2.1.3.2 函数(function)
- 说到函数,我们可以知道有参数和返回值两种
- 写法一:单独指定参数、返回值的类型
- 普通函数:
function 函数名 (参数1: 参数类型, 参数2: 参数类型…): 函数返回数据类型 {} - 箭头函数:
const 函数名 = (参数1: 参数类型, 参数2: 参数类型…): 函数返回数据类型 => {}
- 普通函数:
function add (number1:number, number2: number): number { // 普通函数
return number1 + number2
}
console.log(add(1,2))
const addFn = (number1:number, number2: string): string => { // 箭头函数
return number1 + number2
}
console.log(addFn(2,'fv'))
- 写法二:同时指定参数、返回值的类型(这种方法适用于箭头函数)
const 函数名: (参数1: 参数类型,参数2: 参数类型…) => 函数返回数据类型 = (参数1,参数2) => {}
// 只适用于函数表达式,例子:
const addFn: (number1:number, number2: string) => string = (number1,number2) => {
return number1 + number2
}
- 如果函数没有返回值,那么,
函数返回值类型为:void
function returnvoid(number:number): void {
console.log("函数返回空值", number)
}
returnvoid(2222) //函数返回空值2222
-
使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数了。
- 可选参数: 在可传可不传的参数名称后面添加 ?(问号)
- 注意:必填参数必须在可选参数之前
function mySlice(start:number,end?:number):void {
console.log("开始:" + start + '结束' + end )
}
mySlice(1) //开始1结束undefind
mySlice(1,6) //开始1结束6
2.1.3.3 对象(object)
- JS中的对象是由属性和方法构成的,而TS 中对象的类型就是在
描述对象的结构(有什么类型的属性和方法)。
- 直接使用{}来描述对象结构。属性采用属性名: 类型的形式,方法采用方法名(): 返回值类型的形式
- 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如: greet(name: string): void )
- 在一行代码中指定对象的多个属性类型时,使用; / ,( 分号或者逗号) 来分隔
- 如果一行代码只指定一个属性类型( 通过换行来分隔多个属性类型),可以去掉;(分号)。
- 方法的类型也可以使用箭头函数形式(比如 :{sayHi: () => void1}
// 写法例子
let person: {
name: string,
age: number,
say:() => void,
greet(name:string):void
} = {
name: '李四',
age: 18,
// 注意:我们这里最好是跟上面描述的写法写,便于阅读,当然这么写也不会错
// say(){
// console.log("说hello")
// },
// greet:(name) => {
// console.log("和" + name + "说hello")
// }
say:() => {
console.log("说hello")
},
greet(name) {
console.log("和" + name + "说hello")
}
}
person.say()
person.greet('zs')
console.log(person.name,person.age)
// 写在一行
// let person: {name: string, age: number, say(name:string):void} = {
// name: '李四',
// age: 18,
// say(name) {
// console.log("和" + name + "说hello")
// }
// }
2.1.4 联合数据类型
- 联合数据类型:由两个或者多个其他类型组成的类型,表示可以是这些类型中的任意一种
- 利用 | 连接多个数据类型,| 可理解或者
- 写法:
变量: (数据类型1,数据类型2…)[] = [字面量,……]
// 该写法将|理解成或者,表示arr变量是一个数组,数组里面的值可以有数据类型、字符串类型、null、boolean
const arr: (number | string | null | boolean)[] = [1,'a',false, null]
//该写法表示data可以是number类型、纯字符串数组、存在null/boolean的数组
const data: number | string[] | (null | boolean)[] = ['111']
2.1.5 类型别名(type)
- 类型别名( 自定义类型 ) : 为任意类型起别名
- 使用场景: 当同一类型(复杂 )被多次使用时,可以通过类型别名,简化该类型的使用。
- 使用方法:
使用 type关键字来创建类型别名- 类型别名(比如:a,b…但是最好语义化一些),可以是任意合法的变量名称
- 创建类型别名后,直接使用该类型别名作为变量的类型注解即可
type CustomArray = (number | string)[]
const array1: CustomArray = [1,2,'a','v']
const array2: CustomArray = [2,'a','b']
type a = (number | string)[] | number
const array3: a = [1,2,'a','v']
const array4: a = [2,'a','b']
const number: a = 20
2.1.6 接口(interface)
- 当一个对象类型被多次使用时,一般会使用接口 (interface )来描述对象的类型,达到复用的目的
- 使用方法:
- 使用 interface 关键字来声明接口。
- 接口名称(比如:a,b…但是最好语义化一些),可以是任意合法的变量名称
- 声明接口后,直接使用接口名称作为变量的类型
// 使用接口 -> 这里是两个对象使用的相同键值对以及类型
interface IPerson {
name: string
age: number,
say:() => void,
greet(name:string):void
}
let person1: IPerson = {
name: '张三',
age: 18,
say(){
console.log("说hello")
},
greet:(name) => {
console.log("和" + name + "说hello")
}
}
let person2: IPerson = {
name: '李四',
age: 18,
say(){
console.log("说hello")
},
greet:(name) => {
console.log("和" + name + "说hello")
}
}
// 多个对象有共同的键值对
// let person1: {
// name: string
// age: number,
// say:() => void,
// greet(name:string):void
// } = {
// name: '李四',
// age: 18,
// say(){
// console.log("说hello")
// },
// greet:(name) => {
// console.log("和" + name + "说hello")
// }
// }
// let person2: {
// name: string
// age: number,
// sex: string,
// say:() => void,
// greet(name:string):void
// } = {
// name: '李四',
// age: 18,
// sex: '男',
// say(){
// console.log("说hello")
// },
// greet:(name) => {
// console.log("和" + name + "说hello")
// }
// }
2.1.6.1 类型别名与接口的区别
- 相同点:都可以给对象指定类型
- 不同点:
- 接口(interface)只能给对象指定类型,而类型别名(type)不仅可以给对象指定类型也可以给为任意类型指定别名
- 写法上接口(interface)类似于声明函数,函数中是不同属性/方法的类型描述,而类型别名(type)类似于赋值类型
interface IPerson {
name: string
age: number,
say:() => void,
greet(name:string):void
}
type IPerson = {
name: string
age: number,
say:() => void,
greet(name:string):void
}
type newarr = number | string
2.1.6.2 接口继承(extends)
- 两个接口之间有相同的属性或方法,可以
将公共的属性或方法抽离出来,通过继承来实现复用
interface Point2D {
x: number
y: number
}
// interface Point3D { x: number; y: number; z: number } // 其中x, y是与point2D的x, y相同
// 使用 继承 实现复用:
interface Point3D extends Point2D {
z: number
}
let p3: Point3D = {
x: 1,
y: 1,
z: 0
}
2.1.7 元组(tuple)
- 场景:在一些特殊情况下,例如地图坐标:使用经纬度坐标来标记位置信息。
-
如果我们使用如下方法定义一个数组:
let position: number[]我们从之前的方法可以知道,这其实定义的是一个纯数字类型的数组,长度任意长
let position: number[] = [39, 114, 1, ,3, 4]但是,我们实际需要得到的是坐标信息,只需要有经纬度的值就可以了,如果使用以上方法,后面的值就没有意义了
-
使用元组类型
let position: [number, string] = [39, '114']-
元组:确切的控制了这个数据有多少个元素,以及元素的类型;
-
该例子是定义了一个变量有两个元素,第一个元素是number数据类型,第二个是string类型;
-
如果赋值多了会报错,不对应赋值也会报错,如下所示
-
2.1.8 类型推论
- ts中在某些没有明确指出类型的地方,ts的类型推论机制会帮助提供类型
- 常见场景:1.声明变量并初始化时,2.决定函数返回值时
- 但是如果声明变量没有立即初始化,则必须添加类型注解
否则:
2.1.9 类型断言(as)
-
指定更具体的类型
- as关键字
- 关键字as后面是一个更加具体的类型
const aLink = document.getElementById('link') as HTMLAnchorElement
-
使用<>语法,这种语法形式不常用:(与react语法冲突,不常用)
const aLink = <HTMLAnchorElement>document.getElementById('link') -
获取具体元素的方法**:在浏览器控制台,先选中元素,此时元素后面会被添加$0,通过 console.dir() 打印该 DOM 元素,在属性列表的最后面,即可看到该元素的类型。
2.1.10 字面量类型(const)
-
初体验,代码如下:
let str1 = 'hello' const str2 = 'hello'-
根据类型推论我们可以发现,str1与str2的类型分别是string与 'hello'
-
str1 是一个变量(let),它的值可以是任意字符串;而str2 是一个常量(const),它的值不能变化只能是 'hello'
- 除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用
-
-
使用场景:表示一组明确的可选值列表;一般搭配联合类型一起使用,例如:
2.1.11 枚举(enum)
- 类似字面量类型+联合类型组合的功能,用来表示一组明确的可选值
- 初体验,代码如下:
enum Direction { Up,Down,Right,Left }
function changeDirection(direction: Direction) {
return direction
}
console.log(changeDirection(Direction.Up))
-
输出结果:
-
扩展1:
enum Direction { Up=6,Down,Right,Left }
-
总结:
- 使用
enum关键字定义枚举 - 约定枚举名称、枚举中的值以大写字母开头
- 枚举中的多个值之间通过 ,(逗号)分隔
- 定义好枚举后,
形参直接使用枚举名称作为类型注解 实参的值可以是枚举 Direction 成员的任意一个,接通过点(.)语法访问枚举的成员- 从输出结果为0,我们可以知道表示
枚举的值是会携带默认值的,从 0 开始自增的数值 - 通过扩展1能知道
数字的起始值可以自定义,并且自增只针对数字类型 枚举中的成员也可以自定义初始化值
- 使用
-
字符串枚举:枚举成员的值是字符串
enum Direction { Up = 'up', Down = 'down', Right = 'right', Left = 'left'}
function changeDirection(direction: Direction) {
return direction
}
console.log(changeDirection(Direction.Up))
- 注意: 字符串枚举没有自增长行为,因此,
字符串枚举的每个成员必须有初始值。
-
转换为js文件
- 由于其他类型仅仅被当做类型,而
枚举不仅用作类型,还提供值(枚举不仅作为类型,还提供值);所有其他类型会在编译成js时自动移除,但是枚举会被编译成js代码; - 一般情况下,
推荐使用字面量类型+联合类型组合的方式,相比枚举更加直观、简洁、高效。
- 由于其他类型仅仅被当做类型,而
2.1.12 any类型
- 不推荐使用,当值为any类型时,可以对该值进行任意操作,并且不会有代码提示;也不会有报错,失去了ts的意义
- 其他隐式具有any类型情况:1 声明变量不提供类型也不提供默认值 2 函数参数不加类型
2.1.13 typeof
根据已有的值 来获取值的类型 来简化代码的书写
- 初使用:
let number1: number = 10
let number2 = typeof number1
console.log(number2)
let obj1 = {x: 1, y: 2}
let obj2 = typeof(obj1)
console.log(obj2)
function dot(point: { x: number, y: number }) {
return point
}
console.log(dot(obj1))
function dot2(point: typeof obj1) {
return point
}
console.log(dot2(obj1))
- 使用场景:
根据已有变量的值,获取该值的类型,来简化类型书写 - 如果直接使用typeof,获取的就是获取变量的类型,如上前两个输出
- typeof 出现在
类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于 JS 代码),如上最后一个输出。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
作者:❆VE❆
原文链接:blog.csdn.net/qq_45796592…