-
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
Optional chaining type narrowing of void #35236
Comments
So your request can be broken with something like this: let a: () => void;
let b = () => ({ a: 5 })
a = b;
let c = true;
let d = c ? a() : { a: "5" };
d; // void | { a: string }
console.log(typeof d?.a); // "number" |
@nmain Makes sense, thanks for the clarification |
Actually another question if according to #26262, (a: A | void) => {
a ? a.b : undefined // works
}; Do you think I should file another bug for this? |
Good question. I'm guessing that was intentional, but it does seem inconsistent; |
Testing |
@RyanCavanaugh async (p: Promise<A>) => {
const a = await p.catch(console.error);
// do stuff with a
}; Apparently I know this issue doesn't track this and it's good to close it. But what do you think about such a use case? |
There are also a lot of confusion between const response = mutation();
if (response) {
// This is fine because if(void|{data: Data}) removed void from union
const data = response.data
}
// This is not fine because ?. won't remove void thus giving error that "data" doesn't exist on void
const data = response?.data; While I agree that If you stick to the argument that |
The category of "things which you should not do because they are ultimately incoherent" is unbounded; it's similarly useless to write Banning of certain combinations of type operators and type operands has been discussed extensively before; in a language with structural generics it's ultimately a fool's errand because you can't prevent generic instantiations that end up creating "illegal" types. |
You make a very good point why |
We're actually thinking that the |
Oh, and that |
The biggest problem with making such a change is all the libraries incorrectly using type ReplaceVoid<T> = T extends void ? Exclude<T, void> | undefined : T;
function removeVoid<T>(a: T): ReplaceVoid<T> {
return a as any;
}
type A = void | { data: any };
function foo(a: A) {
// for if block
const _a = removeVoid(a);
if (_a) {
_a.data
}
// using && operator
_a && _a.data;
// using optional chaining
removeVoid(a)?.data;
} Maybe there is an easier way to convert void to undefined, but we'd definitely need it if Typescript is going in that direction. |
TypeScript Version: 3.7.2
Search Terms:
Type narrowing void
Optional Chaining void
Code
Expected behavior:
No errors when using optional chaining with a
T | void
ifT
contains the fields specified. I guessvoid
could be represented as a value asundefined
considering that a function that returnsundefined
returns typevoid
.Not sure if this is feasible
Actual behavior:
compilation error
Playground Link: https://www.typescriptlang.org/play/index.html?ssl=10&ssc=22&pln=10&pc=13#code/C4TwDgpgBAglC8UDeUBGAuKBnYAnAlgHYDmUAvgNwBQVAhliIQMZQAUYmACrgPYC2+LBAA8MAHwBKBGORUoUJj0I4otBKoDutfMChgAdE1rAmAC1aLlPADYR9EXL1wTq82gH59qapRqtamHAAPlAAbjz4ACZS8DJIcqqe3glq7qpeUJgAroSREABmRBCRVL5U-oFQITl5hYTFMXEpST7U5QGwVVCEWdbWjbJuLaXUQA
The text was updated successfully, but these errors were encountered: