-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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 properties coming from conditional spread lose "| undefined" #41418
Comments
@andrewbranch I think we should consider for 4.1 at least; this seems bad |
This is very interesting. It’s actually been a bug at least since 3.8, with #34853, but the new behavior of conditional spreads creating optional properties increases your chances of observing it. Here’s an example of the bug in 3.8.3. Basically, as far as I can tell, we’ve never had the necessary machinery to mix optionality into the type retrieved from a synthetic optional property. The place where we union with Despite having diagnosed the problem, I’m having trouble fixing this in a way that doesn’t broadly change the type printout of these synthetic optional property symbols from |
Hm, that doesn't seem so bad, at least. Certainly better than a synthetic optional property declaration or the like. The other option would be adding a |
Why is it a problem that the printout changes to type Foo = (x?: number) => void; // Prints back as (x?: number | undefined) => void Or am I misunderstanding something? |
It’s not a huge problem, it just changes a bunch of seemingly unrelated baselines, and is more verbose while conveying no more information, so it seems undesirable all other things held equal. |
I tend to agree, but that is nonetheless what we currently do for print back of optional properties. If we're going to change it, we should change it across the board, not just in this targeted scenario. |
Huh, I must have been confused by existing baselines that already exhibit this bug, because I was confident this didn’t happen for property signature printback, but apparently I’m wrong. In that case, I think this is a small change, and we can look at making printback more concise separately. |
Actually, I think the current scheme does convey important information. The type of an optional property really is |
Hmm, actually this causes another break. Consider this case: declare let r: { [key: string]: number };
declare let fromAnnotation: { x?: number };
r = { ...fromAnnotation }; // Error: Type 'undefined' is not assignable to type 'number'.
let fromExpression = { ...!!true ? { x: 3 } : {} };
r = { ...fromExpression }; // Ok The latter works today, and is asserted in a test, only because when we get the type of the |
@andrewbranch much of the discussion in the Design Meeting was about index types. I don't entirely see the connection. Is an index signature somehow involved behind the scenes here? I noticed that the example in the release notes for TS 4.1 RC is also broken because of this issue: interface Person {
name: string;
age: number;
location: string;
}
interface Animal {
name: string;
owner: Person;
}
function copyOwner(pet?: Animal) {
return {
...(pet && pet.owner),
otherStuff: 123
}
}
const owner = copyOwner();
const loc = owner.location; // type is string, should be string | undefined
console.log(loc.blink());
// 💥 Cannot read property 'blink' of undefined |
@danvk a lot of the conversation focused on index signatures because fixing this bug breaks an existing test where an object with optional properties is asserted to be assignable to an index signature. There is no disagreement that the type of the property is a bug, but we can’t fix it this late in the release cycle because the bug has been around at least since 3.8, and fixing it is a breaking change. So, much of the discussion focused on the question of when we do fix the property type, should we consider additional changes to make the assignability of optional properties to index signatures less breaky. |
TypeScript Version: 4.2.0-dev.20201105
Search Terms:
Expected behavior:
The
start
symbols should both have typenumber | undefined
.Actual behavior:
The one destructured from the conditional spread has somehow dropped the
undefined
.Related Issues:
#39376
Code
I'd expect the two
start
variables in the following code to have the same type. But they don't, one isnumber
, whereas the other isnumber | undefined
:Output
Compiler Options
Playground Link: Provided
The text was updated successfully, but these errors were encountered: