-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compiler cannot handle promise.then(null | undefined) #58619
Comments
This is the correct behavior - at runtime, var a = Promise.resolve("hello world").then(null).then(x => console.log(x))
// prints 'hello world' While you might prefer to never allow |
I don’t think that’s the issue that’s being demonstrated here. Minimal repro: const pNumber = Promise.resolve(0);
const pString: Promise<string> = pNumber.then(); // No error The issue is that without a callback argument to |
Whoops, I misread. Apologies. |
The easy fix I thought of was to add an overload for optional |
Yes, there is a real use case, that's how I came across this behaviour. Quoting @DanielRosenwasser :
ie this code should infer function maybeTransform(fn?: (v: number) => string) {
return Promise.resolve(0).then(fn);
} and this code should not compile function maybeTransform(fn?: (v: number) => string): Promise<string> {
return Promise.resolve(0).then(fn);
} Basically it should behave the same way as function maybeTransform(fn?: (v: number) => string) {
return fn ? fn(0) : 0;
} |
I think this can be solved with overloads, but because overload resolution doesn’t happen during inference, I think it’s going to be incredibly breaky. #58678 is up to experiment, but I don’t think it will be viable. |
Probably nobody calls |
interface Promise<T> {
// specific overloads
then<TResult1, TResult2>(
onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>,
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>
): Promise<TResult1 | TResult2>;
then<TResult>(onfulfilled: null | undefined, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected?: null | undefined): Promise<TResult>;
then(onfulfilled?: null | undefined, onrejected?: null | undefined): Promise<T>;
// catch all overload
then<TResult1 = T, TResult2 = never>(
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): Promise<TResult1 | TResult2>;
} This is fairly accurate and works as expected, for the most part. The specific overloads are all mutually exclusive with each other and are designed to avoid introducing a type variable in the return type of Unfortunately, it causes #36307 to regress, so it's still not completely reliable. Ideally, we could solve this during inference by relying on some heuristic related to the fact that |
🔎 Search Terms
"promise", "then", "null", "undefined", "nullable"
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.4.5#code/PTAEBkFMBdQQ1ABwE4HsC2BLAzpU0ALOWAd0wBtzRlJtVyA3PaVUABgG4AoAY1QDtssRKAC8oAAposuAHQ06jSAAo2ASg6guXEKAAqBHKCN9kNHtAA0oPukQVIyY-wBmj7JOk5IAHn4BXdAAjRwA Lhd-fgtMASQ2ZTVQAG8uUHTqGH9kfiRuAF8dMAMjIzhyOhtUM0gLa1t7ckdQJmRMF0xaTwxvP0CQ5FCq-mhkOAsIqJi4xABGRIAubplfAOCwlLSMmmhs3MQCov1DDzKK1lNzaCWGhydIV2qeLqke3B8hNv4AcyG EbGFi0uj0AE9EHgAORrAaQ4wefioWBwbDYTDffhwIJNfCsaDgqGfTA-SGySbRaCxfYAJkWy16RJ Q1SGUyuxyeS4hRBJ1A2AIqH85AAJqBHGgnEF-LBbk0nNg4KDTrAjB1 JBydN9gBmOmvFYfUbE36bVk7PZIWSEB7KAKUDRco4ASRscFyQRRmB45XIoJs5DgmHQ CIsEIqqmlLi5pyHjdoPDP01Uf2ABY9V53gB1YnC1AkUAAH1AABFiHhiwBVABK4CLKXg-AThh SwARDQfaC26B8sytukY-srQQbXbyA7ucVefzBSL4OcxWZqqApTKMI1mgqlcYVR41RrIhSqUgAKwZt6 RkmlnbLIcxAjm1RYWQA-CydAA
💻 Code
// Your code here
🙁 Actual behavior
🙂 Expected behavior
Additional information about the issue
Playground 3.33.3333
Playground 3.5.1
The text was updated successfully, but these errors were encountered: