-
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
Distinguish missing and undefined object properties. #30796
Conversation
So a couple of observations after playing whack-a-mole with I think this change should come paired with some utility package to transform all existing properties: { foo?: Type } ~~~> { foo?: Type | undefined } // if undefined not in Type In theory this should be semantics preserving and allow people to just 'upgrade' without deciding to spend a Saturday doing it manually like some idiots. I don't think this will catch many existing correctness bugs. In most cases the old behaviour was conservative and prevented anything bad happening. The existing mechanisms that can actually distinguish missing or undefined properties seem rarely used. This comes with a big caveat: I'm not someone that uses Where I think this change does shine is in preventing/understanding performance bugs that arise by messing up your object layouts. Assuming legacy properties have been transformed so that they look like: interface Foo {
x?: number | undefined;
} it is now a one character change to track down the places where you don't initialise x explicitly and produce a different shape. If you only have a single location where |
Do you plan to add a |
@leighman As it stands, no I don't plan to. My reason is that conditional types only relate types but I don't claim ownership of this feature or PR, so don't take this as a statement of this is how the feature is going to be. This is just me saying: please don't wait for me to add this. |
@leighman The missing type you’re looking for already exists in the form of |
@ExE-Boss I'm pretty sure interface X { field: never; }
const x: X = {}; doesn't work. A type AllFieldsMissing<T> = {
missing [P in keyof T];
// or
//[P in keyof T]: missing;
};
type AllFieldsOrNone<T> = T | AllFieldsMissing<T>;
type MyType = MyBaseType & AllFieldsOrNone<ExtraFieldGroup>;
interface MyBaseType {
a: number;
b: string;
}
interface ExtraFieldGroup {
c: string;
d: 'some thing' | 'other thing';
e: number;
} I'm pretty sure this can't be implemented yet. |
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
Starts the ball rolling on #13195.
A couple of things to highlight:
I looked into distinguishing optional function arguments too, but I got buried under a mountain of errors in checker.ts. I limited this change to just object properties, which I think is far more useful.
There is some interesting behaviour with index access type now, because they type property access. For example:
So now
B
is not assignable toA
, when it was before.