TypeScript基础知识(一)

184 阅读10分钟

前言

该文章记录一些TS的一些基本知识,后续将会逐步增加,所有内容均从网上整理而来,加上自己得理解做一个整合,方便工作中使用。

一、安装

1.安装TypeScript:npm i -g typescript

二、TypeScript中的基本类型

  • 1.JS原有的简单数据类型

    类型例子描述
    number1, -33, 2.5任意数字
    string'hi', "hi", hi任意字符串
    booleantrue、false布尔值true或false
    undefinedundefined只能是undefined
    nullnull只能是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数组
    functionfunction 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]元组,针对数组,约束数组的每个元素
    enumenum{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)