Description
π Search Terms
exactOptionalPropertyTypes
in the subject line on open and closed issues and PRs in this repository
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
exactOptionalPropertyTypes
is great, and it's been around for a few years by now. It's a recommended option, and having it off means that | undefined
gets implicitly sprinkled around on your types.
I'd like to see this feature enabled by default. It's a clear improvement to the semantics of the language and (with the benefit of hindsight) it probably should have been the way this was done in the first place.
I understand that turning this option on is going to break a lot of existing code (see the above unchecked box edit okay, it forced me to check it), and that this is why it hasn't been done yet. I wonder if the default could be changed to a special mode that's compatible with the old default value (false) but also avoids generating errors caused by undefined
not being compatible with other types. See the example below for the specific case where we're getting in trouble.
In general, though, it would be awesome if there was a mechanism to allow advancing "new defaults" for language features, something akin to Rust "editions". That's a way larger question, though.
π Motivating Example
The main issue is that if you have this feature on in your codebase you can produce APIs that don't work when people try to import/vendor them into their codebase with that option disabled.
We recently got this bug report: cockpit-project/cockpit#21352
In short, we have a "json" type defined in a rather typical way:
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
export type JsonObject = Record<string, JsonValue>;
but then we sometimes say things like
export interface BaseChannelOptions extends JsonObject {
command?: never;
channel?: never;
binary?: boolean;
host?: string;
payload?: string;
superuser?: "try" | "require";
}
to produce an interface which is required to never have the properties command
or channel
present.
This works great with exactOptionalPropertyTypes
but if our code gets used by someone who doesn't have that option set they see an error like:
pkg/lib/cockpit/channel.ts:31:3 - error TS2411: Property 'command' of type 'undefined' is not assignable to 'string' index type 'JsonValue'.
π» Use Cases
See above.
Thanks very much!