一、联合类型和交叉类型
1. 联合类型
- 联合类型是由两个或者多个其他类型组成的类型
- 表示可以是这些类型中分任何一个值
- 联合类型中的每一个类型被称之为联合成员
function printId(id: number | string) {
console.log("ID:", id)
}
printId("abc")
printId(123)
2. 交叉类型
- 交叉类型表示需要满足多个类型的条件
type NewType = number & string
二、type和interface使用
若想要多次使用使用对象、联合等类型,可以使用type/interface避免多次编写
1. 类型别名
type Point = {
x: number
y: number
}
function printPoint(point: Point) {
console.log(point.x, point.y)
}
type ID = number | string
2. 接口的声明
interface IPersson {
name: string
running: () => void
}
3. interface和type的区别
- 如果是定义非对象类型,通常推荐使用type
- 如果是定义对象类型,interface可以重复的对某个接口来定义属性和方法;而type定义的是别名,别名是不能重复的
三、类型断言和非空断言
1. 类型断言as
- 有时候TypeScript无法获取具体的类型信息,这个时候需要用到类型断言
- TypeScript只允许类型断言转换为更具体或者不太具体的类型版本
// 通过document.getElementById,TypeScript只知道该函数会返回HTMLElement,但并不知道具体的类型
const myEl = document.getElementById("my-img") as HTMLImageElement
2. 非空类型断言!
- 确定某个标识符是有值的,这个时候可以使用非空类型断言,跳过ts在编译阶段对它的监测
function printMessage(message?: string) {
console.log(message!.toUpperCase())
}
四、字面量类型和类型缩小
1. 字面量类型
type Alignment = "left" | "right" | "center"
function changeAlign(align: Alignment) {
console.log(align)
}
changeAlign("left")
2. 类型缩小
- typeof
type ID = number | string
function printId(id: ID) {
if (typeof id === "string") {
console.log(id.toUpperCase())
} else {
console.log(id)
}
}
- 平等缩小(switch、===、!==……)
type Direction = "left" | "right" | "center"
function turnDirection(direction: Direction) {
switch(direction) {
case "left":
console.log("left")
break
case "right":
console.log("right")
break
case "center":
console.log("center")
break
default:
console.log("default")
}
}
- instanceof:检查一个值是否是另一个值的“实例”
function printValue(date: Date|string) {
if (data instanceof Date) {
console.log(date.toLocalString())
} else {
console.log(date)
}
}
- in:用于确定对象是否具有带名称的属性
type Fish = { swim: () => void }
type Dog = { run: () => void }
function move(animal: Fish | Dog) {
if ("swim" in animal) {
animal.swim()
} else {
animal.run()
}
}
五、函数的类型和函数的签名
1. 函数类型
- 可以编写函数类型表达式,来表示函数类型
- TypeScript对于传入的函数类型的参数个数不进行监测
type CalcFunc = (num1: number, num2: number) => void
function calc(fn: CalcFunc) {
console.log(fn(20, 30)
}
function sum(num1: number, num2: number) {
return num1 + num2
}
calc(sum)
2. 调用签名
- 如果只是描述函数对象本身,使用函数类型表达式
- 如果在描述函数作为对象可以被调用,同时也有其他属性,使用函数调用签名
- 可以通过调用签名,描述一个带有属性的函数
interface ICalcFn {
name: string
(num1: number, num2: number): void
}
function calc(calcFn: ICalcFn) {
console.log(calcFn.name)
calcFn(10, 20)
}
3. 构造签名
- 在调用签名前面加一个new关键字,可以写一个构造签名
interface IPerson {
new (name: string): Person
}
function factory(ctor: IPerson) {
return ne ctor("why")
}
class Person {
name: string
constructor(name: string) {
this.name = name
}
}
factory(Person)
4. 参数的可选类型
// 可选类型需要在必传参数的后面
function foo(x: number, y?: number) {
console.log(x, y)
}
5. 默认参数
function foo(x: number, y: number = 6) {
console.log(x, y)
}
6. 剩余参数
function sum(...nums: number[]) {
let total = 0
for (const num of nums) {
total += num
}
return total
}
const result = sum(10, 20, 30)
console.log(result)
六、函数的重载和this类型
1. 函数的重载
- 函数的重载
function sum(a1: number, a2: number): number;
function sum(a1: string, a2: string):string;
function sum(a1: any, a2: any): any {
return a1 + a2
}
console.log(sum(20, 30))
console.log(sum("aaa", "bbb"))
- 联合类型和重载
// 需求:定义一个函数,可以传入字符串或者数组,获取他们的长度
// 方案一:使用联合类型来实现(推荐使用)
function getLength(a: string|any[]) {
return a.length
}
// 方案二:使用函数重载来实现
function getLength(a: string): number;
function getLength(a: any[]): number;
function getLength(a: any) {
return a.length
}
2. this类型
- 可推导的this类型
- 在没有制定this的情况下,this默认情况下是any类型的
- this的编译选项
- tsconfig.json ---> "noImplicitThis": true
- 指定的this类型
- 函数的第一个参数可以根据该函数之后被调用的情况,用于声明this的类型(名词必须叫this)
- 在后续调用传入参数时,从第二个参数开始传递的,this参数会在编译后被抹除
function foo(this: { name: string }) { console.log(this) } foo.call({ name: "why" }) - this相关的内置工具
- ThisParameterType:获取一个函数类型Type中this参数类型
- OmitThisParameter:删除this参数类型,剩余的函数类型
- ThisType:用于绑定一个上下文的this