前言
该文章记录一些TS的一些基本知识,后续将会逐步增加,所有内容均从网上整理而来,加上自己得理解做一个整合,方便工作中使用。
一、安装
1.安装TypeScript:npm i -g typescript
二、TypeScript中的基本类型
-
1.JS原有的简单数据类型
类型 例子 描述 number 1, -33, 2.5 任意数字 string 'hi', "hi", hi任意字符串 boolean true、false 布尔值true或false undefined undefined 只能是undefined null null 只能是null
//TS声明变量时同时赋值(也可以先声明变量再赋值)
let userName: string = '胡歌'
let userAge: number = 20
let userStatus: boolean = false
let userLove: undefined = undefined
let userMoney:null=null
-
2.JS原有的复杂数据类型
类型 例子 描述 array [1,2,3] 任意JS数组 function function getTime(){} 任意JS函数 object {name:'孙悟空'} 任意的JS对象
一、数组
1) 变量:类型[] = [xxx]
let arr: number[] = [1, 2, 3]
2) 变量:Array<类型> = [xxx]
let arr2: Array<string> = ['a', 'b', 'c']
3) 多维数组
3-1. type[][]
3-2. Array< Array<type> >
let arr: number[][] = [[1], [2]]
let arr2: Array<Array<string>> = [['1', '2'], ['3', '4']]
二、函数(函数定义参数的类型和本身返回值的类型)
1) 普通函数
function add(a: number, b: number): number {
return a + b
}
add(1,3) //a,b参数只能传入数字,add函数中return也只能返回数字
2) 函数表达式
const add = function(a:number, b:number):number { return a+b }
3) 箭头函数
let add2 = (a: number, b: number): number => a + b
三、对象
1) 规定变量为对象类型
let person: object = {
name: '胡歌',
age: 23
}
//person变量只能被赋值为对象(数组和函数都是对象),其他类型的报错
2) 规定变量具体属性的类型
let student: {
name: string,
age: number,
hobby?: string,
//方法两种方式
study(content: string): void,
playGame: () => void,
}
// 变量接收的赋值必须和规定的内容一样,不能多/少属性
// ?:表示这个属性[可选],可有可无
student = {
name: '胡歌',
age: 20,
hobby: '骑车',
study: (content: string) => {
console.log(content)
},
playGame() {
console.log(this.name + this.sex)
},
}
student.hobby?.toLocaleLowerCase() // ?. 表示条件判断,有hobby这个属性,才执行它的方法
3) 变量规定object添加任意属性
let student: {
[propName: string]: any ,
}
// 注意:使用[propName: string]要求其他属性的类型必须与其一致,否者用any
// 例如:let status:{name:string, [propName:string]:number } 错误的
student = {
name: '胡歌',
age: 123,
hobby: { one: '唱歌', two: '跳舞' }
}
-
3.TS新增数据类型
类型 例子 描述 字面量 其本身 限制变量的值就是该字面量的值 any * 任意类型 unknown * 不确定类型,可以接收任意类型的值 void 空值(undefined) 没有值(或undefined) never 没有值 不能是任何值 tuple [4,5] 元组,针对数组,约束数组的每个元素 enum enum{A, B} 枚举,TS中新增类型
一、字面量(直接使用字面量进行类型声明,类似用const定义变量)
1) 普通使用
let student:'李白' = '李白'
//与const student = '李白'效果一样
let a: string = '李白'
//student = a 报错,已经是单独的数据类型,不再是字符串类型
let person: {name:string, age:number}={
name:'胡歌',
age:20
}
2) 联合类型
let studentNo: 0 | '0' | null
studentNo= 0 //'0' null
3) 配合type使用
type Direction = '上' | '下' | '左' | '右'
let button : Direction = '上' //只是是'上下左右'其中一个值
二、void类型(函数没有返回值)
//如果函数中不写return,ts默认函数返回值类型为 void
const add = () => {}
三、元组tuple(针对数组,约束数组的每个元素)
let num:number[]= [1,2,3,4,···] //普通数组类型不能单独限制每个元素
//使用元组:[类型,类型]
let map: [number, number] = [1, 2]
let map: [number, number] = [1, 2,3]//报错
let map: [number, number] = [1, 'a']//报错
四、枚举enum
//枚举不设置值时,默认从0开始累加1
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up) //0
console.log(Direction.Down) //1
console.log(Direction.Left) //2
console.log(Direction.Right)//3
//枚举设置数字类型的值时,从初始值开始累加1
enum Direction {
Up = 100,
Down,
Left = 200,
Right
}
console.log(Direction.Up) //100
console.log(Direction.Down) //101
console.log(Direction.Left) //200
console.log(Direction.Right)//201
//枚举也可以设置成其他类型的值,但是必须都要设置
enum Direction {
Up = '上',
Down = '下',
Left = '左',
Right = '右'
console.log(Direction.Up) //上
console.log(Direction.Down) //下
console.log(Direction.Left) //左
console.log(Direction.Right)//右
- 4.补充
//类型级别(级别高的包含级别低的)
// 1. any unknown
// 2. Object
// 3. Number String Boolean
// 4. number string boolean
// 5. 1 'abc' false
// 6. never
// unknown 只能赋值给自身或者是any
// unknown 没有办法读取自身任何属性,方法也不可以调用
// unknown 比any 在不知道具体类型时,相对安全一些
// Object 类型
let a1:Object=123
let a2:Object='abc'
let a3:Object=false
let a4:Object=[]
let a5:Object={}
let a6:Object=()=>123
// object 类型
// let b1:object=123 //错误
// let b2:object='abc' //错误
// let b3:object=false //错误
let b4:object=[]
let b5:object={}
let b6:object=()=>123
三、TS类型的特殊使用方法
1.类型联合使用
变量的数据类型是动态的,可能是数字类型,也可能是字符串类型,使用联合类型就可以使变量被赋值为多种类型,
使用'|'联合不同类型关键字
//需求:学生编号既能是数字类型,也可以是字符串类型
let studentNo: number | string
studentNo = 1
studentNo = '001'
//需求:数组可以存数字类型,也可以存字符串类型或者对象类型
let person:(number | string | object)[]
person = [1, 3, 4]
person = [1, 3, 'a', { name: '胡歌' }]
//需求:变量接收定时器
let timer:number | null = null
timer = setTimeout(() => {} , 1000)
2.类型别名
类型别名即为为任意类型起别名,当同一复杂的联合类型被多次使用时,可以通过类型别名,简化该类型的使用。使用
type关键字来创建自定义类型
1) 类型别名最好首字母大写
type PersonType = (number | string | object)[]
let person: PersonType
person = [1, 3, 4]
person = [1, 3, 'a', { name: '胡歌' }]
2) 可以搭配使用
type StudentNoType = number | string | object
let xiaoming: StudentNoType = '001'
let student: StudentNoType[] = [1, 'abc']
let students: Array<StudentNoType> = [2, 'x',{name:'胡歌'}]
3) 函数的类型别名(箭头函数/函数表达式使用)
type Addfunction = (a:number, b:number) => number
let add: Addfunction = (a, b) => a + b
const add2: Addfunction = function(a, b) { return a + b }
3.可选参数
有时候不需要固定死参数,比如函数中,有些形参可传可不传,使用
?表示参数是可选参数
1) 函数的参数:必选参数在可选参数前面
const printName = (name: string, funing?: string): void => {
console.log(name, funing)
}
printName('胡歌')
printName('胡歌', '骑车')
2) 对象的属性、方法
type Student = {
name: string,
sex: string,
money?: number,
sayhi?: (a: number, b?: number) => number,
game?(a: number, b: number): void
}
let xiaoming: Student = {
name: '小明',
sex: '男',
sayhi(a: number, b?: number) {
return 10 * a + (b || 0)
}
}
let xiaohong: Student = {
name: '小红',
sex: '女',
money: 1000,
game: (a: number, b: number) => a * b * 100
}
4.接口类型以及继承
我们定义对象的方式要用关键字
interface(接口),与type的区别,interface只能约束对象,type可以更灵活的使用。
//变量名建议I开头
interface IPerson {
name: string,
age: number,
sayHi: () => void
}
const xiaoming: IPerson = {
name: '谷歌',
age: 19,
sayHi() {
console.log('我是谷歌')
}
}
xiaoming.sayHi()
2)向已有的接口添加新的字段,同名接口不会覆盖,会叠加,两者相同属性的类型不能冲突
interface MyInfo {
readonly name: string, // readonly只读属性
sex: boolean
}
interface MyInfo {
hobby: string,
[propName: string]: any,
cb: (sex: string) => string //( 参数:类型 )=> 类型
}
let student: MyInfo={
name:'胡歌',
sex:false,
hobby:'打篮球',
food:'水饺',
cb: () => {
return 'abc'
}
}
3) 接口用来规范函数(只能用函数表达式)
interface Print {
(name: string): Array<string>
}
let printString: Print = function (content: string) {
return [...content]
}
接口继承,使用
extends关键字,子级接口继承父级接口所有约束规则
interface IPerson {
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
//继承: interface 子级 extends 父级
interface IStudent extends IPerson {
score: number
study(content: string): void
}
const xiaoming: IStudent = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
score: 123,
study(content: string) {
console.log(content)
}
}
5.交叉类型('&')以及联合类型('|') - interface和type
1.使用
&符号,实现type自定义类型的继承效果
type Person ={
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
type Student = {
scorre: number
study(content: string): void
} & Person //使用& 链接两个type自定义类型,使得Student继承了Person所有约束规则
const xiaohong: Student = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
scorre: 123,
study(content: string) {
console.log(content)
}
}
2.type和interface通过
&链接,类似继承效果
1)type继承interface的约束规则 :type XXX = {} & 变量(interface)
interface IPerson {
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
type Student = {
scorre: number
study(content: string): void
} & IPerson
const xiaohong: Student = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
scorre: 123,
study(content: string) {
console.log(content)
}
}
2) interface 继承 type的约束规则: interface XXX extends 变量(变量){}
type Person ={
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
interface IStudent extends Person {
scorre: number
study(content: string): void
}
const xiaohong: IStudent = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
scorre: 123,
study(content: string) {
console.log(content)
}
}
3) 直接&连接使用: type & interface / type & type / interface & interface
type Person ={
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
interface IStudent {
scorre: number
study(content: string): void
}
const xiaohong: Person & IStudent = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
scorre: 123,
study(content: string) {
console.log(content)
}
}
使用
|联合type 和 interface,满足其中一方全部约束规则,剩下一方规则都是可选
// type | type // type | interface // interface | interface
interface IPerson {
name: string,
sex: 'woman' | 'man',
age: number,
sleep: () => void
}
type Student = {
scorre: number
study(content: string): void
}
const xiaohong: IPerson | Student = {
name: '谷歌',
age: 19,
sex: 'man',
sleep() {
console.log('人类需要睡觉')
},
}
const xiaoming: IPerson | IStudent = {
scorre: 123,
study(content: string) {
console.log(content)
}
}
6、类型推断
类型推断即当没有声明类型时,TS自动赋予了类型,主要发生在两种情况下
一、声明变量时直接赋值
//ts根据赋值,默认a的类型为number
let a = 10
二、函数没有规定返回值类型时
// ts推断为函数返回值类型为void
function add(){}
7、类型断言
类型断言的作用:将变量的类型指定为编译器无法自动推断的类型,将一个数据类型强制转换为其他数据类型,当实际开发中应该尽可能确保类型转换的安全性,否则可能会导致意外的运行时错误。
// 需要将a的值赋值给b,确定了类型类型一致,才能赋值
let a: unknown
let b: number
// b=a 报错
//方法一:if判断,同类型才执行赋值
if (typeof a == 'number') {
b = a
}
//方法二: 使用类型断言, 将变量a强行变成number类型,赋值给b
b = a as number //写法一: 变量 as 类型/类型别名
b = <number>a //写法二: <类型>变量
//当需要获取元素时,需要使用到类型断言
const a = document.getElementById('link') //此时a的类型是 'HTMLElement | null'
a.href = 'xxx' //报错,a类型不存在href属性
//使用类型断言,将a类型强行改为'HTMLAnchorElement'
const a = document.getElementById('link') as HTMLAnchorElement
a && (a.href = 'xxx') //正常
8、内置对象的类型
//一、 ECMA Script的内置对象
let num: Number = new Number()
let data: Date = new Date()
let reg: RegExp = new RegExp(/x/)
let error: Error = new Error()
let xhr: XMLHttpRequest = new XMLHttpRequest()
//二、DOM
//1.单个元素
// 1) 动态会变:HTML+元素名称+Element
let div: HTMLDivElement | null = document.querySelector('div')
let input: HTMLInputElement | null = document.querySelector('input')
// 2) 固定的: HTMLElement
let footer: HTMLElement | null = document.querySelector('footer')
// 3) 可以都直接断言成 Element
let head = document.querySelector('head') as Element
//2.元素集合
//1) 同类元素集合 NodeList
let footers: NodeList = document.querySelectorAll('footer')
//2) 不同元素集合 NodeListOf<>
let elements: NodeListOf<HTMLDivElement | HTMLInputElement> = document.querySelectorAll('div input')
//三、BOM
let localSxx: Storage = localStorage
let loca: Location = location
let cookie: string = document.cookie
let promise: Promise<number> = new Promise((resolv) => {
resolv(1)
})
promise.then(res => {
//res是number类型
})
//代码雨
let canvas: any = document.querySelector('canvas')
let ctx = canvas?.getContext('2d')
canvas.width = screen.availWidth
canvas.height = screen.availHeight
let str: string[] = 'gtxiaoyang1314'.split('')
let arr: number[] = Array(Math.ceil(canvas.width / 10)).fill(0)
setInterval(() => {
ctx.fillStyle = 'rgba(0,0,0,.05)'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = '#0f0'
arr.forEach((item, i) => {
ctx.fillText(str[Math.floor(Math.random() * str.length)], i * 10, item + 10)
arr[i] = item > canvas.height || item > 10000 * Math.random() ? 0 : item + 10
})
}, 40)