三、TypeScript类型补充

108 阅读7分钟

函数的入参和返回值

函数是JavaScript非常重要的组成部分,TypeScript允许我们指定函数的参数和返回值的类型。并且如果函数定义时候传入了几个必选参数,那么调用的时候就得传多少个参数。

参数的类型注解

function sum(num1: number, num2: number) {
  return num1 + num2
}

函数的返回值类型

我们也可以添加返回值的类型注解,这个注解出现在函数列表的后面:

function sum(num1: number, num2: number):number {
  return num1 + num2
}

和变量的类型注解一样,我们通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型:

image.png

匿名函数的参数

image.png

item根据上下文的环境推导出来的, 这个时候可以不添加的类型注解 上下文中的函数: 可以不添加类型注解

对象类型

如果我们希望限定一个函数接受的参数是一个对象,我们使用了一个对象来作为类型

function printPoint(point: {x: number, y: number}) {
  console.log(point.x);
  console.log(point.y)
}

printPoint({x: 123, y: 321})

可选类型

对象类型也可以指定哪些属性是可选的,可以在属性的后面添加一个?:

function printPoint(point: {x: number, y: number, z?: number}) {
  console.log(point.x)
  console.log(point.y)
  console.log(point.z)
}

printPoint({x: 123, y: 321})
printPoint({x: 123, y: 321, z: 111})

函数参数可选

function add(num1: number, num2: number, num3?: number) { 
}
add(1, 2)
add(1,2,3)

联合类型

联合类型是由两个或者多个其他类型组成的类型

表示可以是这些类型中的任何一个值;

联合类型中的每一个类型被称之为联合成员(union's members);

function printID(id: number|string|boolean) {
  // 使用联合类型的值时, 需要特别的小心
  // narrow: 缩小
  if (typeof id === 'string') {
    // TypeScript帮助确定id一定是string类型
    console.log(id.toUpperCase())
  } else {
    console.log(id)
  }
}

printID(123)
printID("abc")
printID(true)

可选类型可以看做是 类型 和 undefined 的联合类型,唯一不同的是可选类型可以直接foo(),而联合类型需要传入undefined。

function foo(message?: string) {
  console.log(message)
}
function foo1(message: string|undefined) {
  console.log(message)
}
foo("1")
foo()          //可以不传undefined
foo(undefined)

foo1("1")
foo1(undefined) //必须传undefined

类型别名

在前面,我们通过在类型注解中编写 对象类型 和 联合类型,但是当我们想要多次在其他地方使用时,就要编写多次。这个时候可以给对象类型和联合类型起一个别名:

// type用于定义类型别名(type alias)
type IDType = string | number | boolean
type PointType = {
  x: number
  y: number
  z?: number
}

function printId(id: IDType) {

}

function printPoint(point: PointType) {
  
}

类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。

语法:

值 as 类型


let str: any = 'hello world'
let num: number = (str as string).length
console.log(num) // 11

非空类型断言

非空类型断言(Non-null Assertion)是TS的一个特殊语法,可以用来从一个可能为null或undefined的值中排除null和undefined。在变量名后面加上!即可

// message? -> undefined | string
function printMessageLength(message?: string) {
  // if (message) {
  //   console.log(message.length)
  // }
  console.log(message!.length)   //但是其实只是编译时候是这个逻辑,如果传入个undefined进来,
}//运行时依旧会报错。

在这个例子中,我们将函数入参为可选类型(message的类型定义为string | undefined),即可能为字符串或undefined。但是在使用message.length时,TS会报错,因为message有可能为undefined,而undefined是没有length属性的。这时我们可以使用非空类型断言来排除undefined,即在str后面加上!,告诉TS这个值一定不为null或undefined。这样TS就不会报错了。

可选链

可选链(Optional Chaining)是TS3.7中新增的一个特性,可以用来简化代码中对于可能为null或undefined的属性或方法的访问。

可选链使用可选链操作符 ?.。它的作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行;虽然可选链操作是ECMAScript提出的特性,但是和TypeScript一起使用更版本。

!.和?.区别

  • 可选链使用可选链操作符 ?.。它的作用是当对象的属性不存在时,会短路,直接返回undefined
  • 而!.虽然逃过了编译阶段报错,但是如果没有传入参数或者传入了undefined当调用.length时,运行时还是会报错。(编译时排除了null和undefined,但是运行时依旧能传入undefined,null)
  • 如果使用message?.length就会直接返回undefined,不会报错。所以大多情况使用可选链。

??和!!操作符

!!操作符:

  • 将一个其他类型转换成boolean类型;

  • 类似于Boolean(变量)的方式;

??操作符:

  • 它是ES11增加的新特性;

  • 空值合并操作符(??)是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数;

字面量类型

字面量类型是 TypeScript 中的一种类型,它允许你指定变量的值只能是某些特定的值。字面量类型有以下几种:

  1. 字符串字面量类型:用来指定字符串变量的值只能是某些特定的字符串,例如:
type Direction = "north" | "east" | "south" | "west";
let dir: Direction = "north"; // 可以
dir = "up"; // 报错

  1. 数字字面量类型:用来指定数字变量的值只能是某些特定的数字,例如
type Answer = 42;
let a: Answer = 42; // 可以
a = 43; // 报错

  1. 对象字面量类型:用来指定对象变量的属性名和属性值的类型,例如
type Person = {
  name: string;
  age: number;
  gender: "male" | "female";
};
let person: Person = {
  name: "Tom",
  age: 18,
  gender: "male",
};

  1. 数组字面量类型:用来指定数组变量的元素类型和元素个数,例如:
type StringArray = ["hello", "world"];
let arr: StringArray = ["hello", "world"]; // 可以
arr = ["world", "hello"]; // 报错

字面类型推导

let str = "hello" as const; // str 的类型被推导为 "hello" 类型
let num = 123 as const; // num 的类型被推导为 123 类型
let arr = [1, 2, 3] as const; // arr 的类型被推导为 readonly [1, 2, 3] 类型
let obj = { name: "Tom", age: 18 } as const; // obj 的类型被推导为 { readonly name: "Tom", readonly age: 18 } 类型

注意,使用 as const 可以将变量的类型推导为字面量类型或只读数组/对象类型,但是不能将变量的类型推导为只读字符串/数字/布尔类型,

image.png

上面图片上如果21行没有as const,那么23行的第二个参数会被认为是string类型,和声明的Method类型冲突,所以会报错。如果有as const 就会把23行第二个参数弄成只读"POST"字面量对象,因此不会报错。

枚举类型

在 TypeScript 中,枚举类型是一种用于表示一组有限的命名常量的工具。枚举类型可以使代码更加清晰和易于理解,同时还可以提高代码的健壮性和可靠性。

下面是一个使用枚举类型的示例:

// type Direction = "left" | "Right" | "Top" | "Bottom"

enum Direction {
  LEFT,
  RIGHT,
  TOP,
  BOTTOM,
}

function turnDirection(direction: Direction) {
  switch (direction) {
    case Direction.LEFT:
      console.log("改变角色的方向向左");
      break;
    case Direction.RIGHT:
      console.log("改变角色的方向向右");
      break;
    case Direction.TOP:
      console.log("改变角色的方向向上");
      break;
    case Direction.BOTTOM:
      console.log("改变角色的方向向下");
      break;
    default:
      const foo: never = direction;
      break;
  }
}

turnDirection(Direction.LEFT);
turnDirection(Direction.RIGHT);
turnDirection(Direction.TOP);
turnDirection(Direction.BOTTOM);

枚举类型的值


// type Direction = "left" | "Right" | "Top" | "Bottom"

enum Direction {
  LEFT = "LEFT",
  RIGHT = "RIGHT",
  TOP = "TOP",
  BOTTOM = "BOTTOM"
}



function turnDirection(direction: Direction) {
  console.log(direction)
  switch (direction) {
    case Direction.LEFT:
      console.log("改变角色的方向向左")
      break;
    case Direction.RIGHT:
      console.log("改变角色的方向向右")
      break;
    case Direction.TOP:
      console.log("改变角色的方向向上")
      break;
    case Direction.BOTTOM:
      console.log("改变角色的方向向下")
      break;
    default:
      const foo: never = direction;
      break;
  }
}
const direction: Direction = Direction.TOP;
console.log(direction); // 输出 "TOP"
turnDirection(Direction.LEFT)
turnDirection(Direction.RIGHT)
turnDirection(Direction.TOP)
turnDirection(Direction.BOTTOM)

export {}