ts中的void和never

42 阅读2分钟

void和never都是函数返回类型的一种,但是它们有很大的区别。void表示函数不返回任何值,而never表示函数永远不会返回。在实际编程中,void通常用于表示函数执行了某些操作但不需要返回值,而never通常用于表示函数会抛出异常或陷入无限循环等情况,从而永远不会返回。

void

表示函数执行了某些操作但不需要返回值。举个例子:

function f1() {
  console.log(123)
}
function f2() {
  return
}
// 这两种情况下函数的类型为void,比较容易理解

never

表示函数会抛出异常或陷入无限循环等情况,从而永远不会返回,而且never类型的参数只能接受never类型的对象。 举个例子:

// 抛出异常
function f3(): never {
  throw new Error('抛出异常')
}

// 无限循环
function f4(): never {
  while(true) {}
}

乍一看,好像没啥用,再仔细一看,好像确实没啥用。

不过对于never也有对应的使用场景,可以验证逻辑判断是否准确。举例如下:

function f5(val: number | string) {
  switch (typeof val) {
    case 'number':
      // 类型为number进行的处理
      break;
    case 'string':
      // 类型为string进行的处理
      break;
    default:
      break;
  }
}

函数f5中,根据参数val不同的类型分别进行不同的操作,这里没有什么问题。

但是如果参数val再加一个object类型,这个时候如果下面switch中忘记写对应的处理,代码层次上是没有问题的,但是逻辑上是不符合我们要求的,如下:

// 参数有object类型,但是未对object进行单独处理,代码也不会报错
function f5(val: number | string | object) {
  switch (typeof val) {
    case 'number':
      // 类型为number进行的处理
      break;
    case 'string':
      // 类型为string进行的处理
      break;
    default:
      break;
  }
}

所以,此时就可以借助never进行判断,在default块中加上一个never类型的参数并赋值为val,由于任何类型的值都不能赋值给never类型的参数,所以此处到default时的类型为object,就会报错。

function f5(val: number | string | object) {
  switch (typeof val) {
    case 'number':
      // 类型为number进行的处理
      break;
    case 'string':
      // 类型为string进行的处理
      break;
    default:
      const check: never = val
      break;
  }
}

想要避免错误,只需要把object的判断加上,而且如果逻辑完全正确也不会走到default

function f5(val: number | string | object) {
  switch (typeof val) {
    case 'number':
      // 类型为number进行的处理
      break;
    case 'string':
      // 类型为string进行的处理
      break;
    case 'object':
      // 类型为object进行的处理
      break;
    default:
      const check: never = val
      break;
  }
}