在 TS 中将 undefined 转换为 void 是否可以?

Is it OK to cast undefined to void in TS?

TLDR;

这样可以吗?或者这是不好的做法?

function isUndefined (payload: any): payload is undefined | void {
  return payload === undefined
}

上下文

在 TypeScript 中,我有一个函数可以 return 或 undefinedvoid

类似于可以 return 修改有效负载的事件处理程序,或者开发人员可以选择 return 什么都没有或未定义,以防他们不会修改有效负载:

function eventHandler <T extends {[key: string]: any}> (payload: T): Modified<T> | undefined | void {
  // ... implementation
}

然后我有一个类型检查器需要检查它是否 returning void 或 undefined 以外的东西:

const result = eventHandler(payload)

if (result !== undefined) {
  // we have a modified payload!
}

但是,上面的代码片段是否出现错误,因为它说即使 result !== undefined 它仍然可以是 void

在我看来,我认为这很奇怪,因为void应该与undefined相同。

所以我做了这个类型检查器来解决它:

function isUndefined (payload: any): payload is undefined | void {
  return payload === undefined
}

这解决了我的问题,但我的问题是:

这样可以吗?或者这是不好的做法?

void 不是 undefinedvoid 表示缺少 return 值。 undefined 是 运行 时未定义的值的类型。

一个函数 returns 在 运行 时间 returns undefined 确实没有值,但是在 TS 类型系统中我们选择了缺少 return 特殊值。

例如分配 (a) => void to (a) => number | undefined 可能是一个错误,尽管它在 运行 时是安全的。

除了return类型的函数外,一般不要使用void。对于其他所有内容,请使用 undefined.

所以,是的,我们需要对 undefinedvoid 使用不同的检查。

我认为你把它变得更复杂了。 returns void 可以的函数:

  1. 没有return声明
  2. 有一个未指定值的 return; 语句。
  3. 有一个return undefined;声明。

在纯 javascript 中,以上所有项的 return 值为 undefined。如果你说一个函数 returns undefined,那么你只能做上面列表中的 #2 和 #3。

所以你可以只拥有一个函数类型,将 void 与任何你想要的 something 结合起来。

function foo(): string | void {
    return Math.random() > 0.5 ? 'abc' : 123
}

const val = foo()
if (val === undefined) {
    console.log('is undefined', val)
} else {
    console.log('is some value', val)
}

这意味着您可以创建一个通用函数类型来修改有效负载,如下所示:

type PayloadModifier<T extends {[key: string]: any}> = (payload: T) => T | void

const setMaxAsTen: PayloadModifier<{a: number}> = (payload) => {
    if (payload.a > 10) {
        return { a: 10 }
    }
    return undefined // required unless noImplicitReturns is false
}

const val = setMaxAsTen({a: 5})
if (val === undefined) {
    console.log('is undefined', val)
} else {
    console.log('is some value', val)
}

Playground

最后要注意的是,有一个编译器选项可以保留在 called noImplicitReturns 上。如果函数在任何执行分支中声明了一个 return 值,则必须在每个执行分支中声明一个 return 值。所以因为上面有时 return 是一个值,如果你不 return 一个有效负载,你必须明确地 return undefined。您可以关闭该选项,允许您省略该行,但不推荐这样做,因为它确实可以帮助您捕获一些错误。