函数应返回Promise <string>,显然返回Promise <unknown>,但仍可编译

时间:2019-12-20 09:53:38

标签: typescript

这是我遇到的一些奇怪的代码。我已经修复它,但是我不明白为什么为什么正在编译:

const stringOrNull: () => Promise<string | null> = () =>
  Promise.resolve(Math.random() < 0.5 ? "Hello, world." : null);

// why does this compile?
const stringOrNullWeird: () => Promise<string> = () =>
  new Promise(resolve =>
    stringOrNull().then(result => resolve(result ? result : undefined))
  );

// will eventually crash with
// (node:20784) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'toLocaleLowerCase' of undefined
[...Array(10).keys()].forEach(async () =>
  console.log((await stringOrNullWeird()).toLocaleLowerCase())
);

我通过简单地将返回的Promise放在一个临时变量中来重写了该函数,因此我可以检查TypeScript推断的类型:它似乎是unknown,然后 then 函数无法编译。

// does not compile, as expected
// Type '() => Promise<unknown>' is not assignable to type '() => Promise<string>'.
//   Type 'Promise<unknown>' is not assignable to type 'Promise<string>'.
//     Type 'unknown' is not assignable to type 'string'.ts(2322)
const stringOrNullUnknown: () => Promise<string> = () => {
  // const p: Promise<unknown>
  const p = new Promise(resolve =>
    stringOrNull().then(result => resolve(result ? result : undefined))
  );
  return p;
};

所以我不明白第二种形式与上面的形式有何不同,为什么上面的一种可以编译,破坏了类型的安全性?

1 个答案:

答案 0 :(得分:0)

实际上,原因不是Promise<unknown>可分配给Promise<string>。当将new Promise分配给期望的Promise<string>所在的位置时,TS会得出new Promise(..)确实是new Promise<string>(...)的信息。当像第二个示例一样将其放入变量中时,TS将无处知道类型参数是什么,并且与unknown一起使用。

允许这样做的真正原因是,这是Promise构造函数的签名:

new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;

请注意,对于resolvevalue是可选的,因此undefined是可接受的值。 issue表示已解决,但由于here

所述的其他地方会产生不可预见的后果,因此更改被撤消。

尽管如此,我还是建议一般避免使用Promise构造函数:

const stringOrNullWeird: () => Promise<string> = () =>
  stringOrNull().then(result => result ? result : undefined);

以上内容比较简单,可能会出错。 或者,如果您的异步逻辑变得过于复杂,请使用async / await

const stringOrNullWeird: () => Promise<string> = async () => {
  const result = await stringOrNull()
  return result ? result : undefined;
}

两个都将是错误。调用Promise构造函数通常是多余的。