Typescript 函数应返回承诺<;字符串>;,显然回报承诺<;未知>;但仍在编译

Typescript 函数应返回承诺<;字符串>;,显然回报承诺<;未知>;但仍在编译,typescript,Typescript,下面是我遇到的一些奇怪的代码。我已经修复了它,但我不明白它为什么会编译: const stringOrNull:()=>Promise=()=> Promise.resolve(Math.random()Promise=()=> 新承诺(解决=> stringOrNull()。然后(结果=>解析(结果?结果:未定义)) ); //最终将与 //(节点:20784)未经处理的PromisejectionWarning:TypeError:无法读取未定义的 […数组(10).keys()].forE

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

const stringOrNull:()=>Promise=()=>
Promise.resolve(Math.random()<0.5?“你好,世界。”:null);
//为什么要编译?
const stringornullwird:()=>Promise=()=>
新承诺(解决=>
stringOrNull()。然后(结果=>解析(结果?结果:未定义))
);
//最终将与
//(节点:20784)未经处理的PromisejectionWarning:TypeError:无法读取未定义的
[…数组(10).keys()].forEach(异步()=>
console.log((wait stringornullwird()).toLocaleLowerCase())
);
我重写了这个函数,只需将返回的
Promise
放在一个临时变量中,这样我就可以检查TypeScript推断出的类型:它似乎是
unknown
,然后函数就不会编译了

//未按预期编译
//类型“()=>Promise”不可分配给类型“()=>Promise”。
//类型“Promise”不可分配给类型“Promise”。
//类型“未知”不可分配给类型“字符串”。ts(2322)
const stringOrNullUnknown:()=>Promise=()=>{
//警察:答应我
const p=新承诺(解析=>
stringOrNull()。然后(结果=>解析(结果?结果:未定义))
);
返回p;
};

因此,我不明白第二种形式与上面的形式有何不同,以及为什么上面的形式会编译,破坏类型安全?

事实上,原因不是
Promise
可分配给
Promise
。当您将
新承诺
分配给预期的
承诺时,TS将发现
新承诺(…)
实际上是
新承诺(…)
。在第二个示例中,当您将其放入变量中时,TS将无法确定类型参数是什么,并使用
unknown

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

new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
上述情况更简单,可能是一个错误。 或者,如果异步逻辑变得太复杂,请使用
async
/
wait

const stringOrNullWeird: () => Promise<string> = async () => {
  const result = await stringOrNull()
  return result ? result : undefined;
}
const stringornullwird:()=>Promise=async()=>{
const result=await stringOrNull()
返回结果?结果:未定义;
}
两者都是错误。调用
Promise
构造函数通常是多余的

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