-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Syntax for conditionally setting object properties #45606
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
Comments
After writing this, I found #39376. It predates |
This request seems to require runtime stuff. Likely the better place for this feature of only setting the key would be the JS specification itself ( https://tc39.es/ecma262/ ). |
@bmeck As I mentioned in the proposal, this doesn't require any more runtime behavior than creating a class method or using the elvis operator. The reason I don't think it belongs in the JS spec, as I outlined, is this isn't a problem for JS, it's a unique problem to TS. Why would the JS spec want to solve a TS problem? |
Youβre right, I doubt TC39 would want this. But we canβt take it either, because it is a runtime feature. |
But it's not. You have the same issue in JS: You optionally want to set a property. You don't want a property with an |
It is possible to write this inside the object literal with:
So I am wondering whether it is possible to introduce a different syntax for that, like e.g.
and transform it into the above. |
This is what I'd like to be able to write! Would it be a Javascript feature, then? |
That is the problem that I was asking about. If it is was implemented as a custom feature in javascript, which is transformed by a babel-plugin for now, typescript would still have to understand it. Naively we could also try to build a preprocessor which converts function includeIfSet<K extends string, V>(key: K, value?: V) {
if (value === undefined) {
return {};
}
return { [key]: value };
} Having a solution directly in typescript would be much cleaner though. |
Suggestion
π Search Terms
conditionally assigned properties conditional properties exactOptionalPropertyTypes
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Create a syntax for conditionally assigning a property in an object at creation time in-line. This is especially relevant now that exactOptionalPropertyTypes is launched. See below for a proposal of how to do this.
π Motivating Example
Imagine this piece of JavaScript code:
This is valid JS code, and a somewhat common pattern for setting an optional property on an object.
But how would we convert this into strict TypeScript code, particularly with immutable types? Perhaps something like:
Well that doesn't work. :-(
Another option before exactOptionalPropertyTypes was:
But this is bad practice for the reasons outlined in exactOptionalPropertyTypes, and is an error if you use that flag now.
Using good practices combined with strict TypeScript settings is preventing us from accomplishing this somewhat common pattern for constructing immutable objects with some optional properties. One workaround is to use something like
type Mutable<T> = {-readonly [key in keyof T]: T[key]}
inside this function, but this is worsening type scritness by circumventing the original type's immutability. Or you could tell the compiler to assume the value is non-null (!
), then conditionally delete that property after, but that's error-prone and is circumventing TypeScript's type checking. I'm not aware of any safer way to do this without fundamentally modifying the code (eg. creating a builder pattern).Proposal
What if we had something like this:
This code would compile to the JavaScript code written at the top of this FR. But importantly, unlike my other examples, this code will build successfully because TypeScript understands the optional (but not undefined) key will not be set on this object unless its value is defined. It is type-safe.
How isn't this just a new syntactic sugar for JavaScript?
This problematic code is unique to TypeScript. JavaScript has simple solutions that build and run just fine (see first code example), but TypeScript does not (without sacrificing strictness). As such, this problem falls in the realm of TypeScript to solve, as JavaScript has far less incentive to implement what for them would only be a very minor syntactic sugar rather than a fix for unsupported use-cases.
Additionally, this is not writing any code that a human wouldn't write themselves if asked to solve this problem in JavaScript. This would just be TypeScript equivalent syntax that transpiles to that form, in the same way TypeScript class methods transpile to
MyClass.prototype.foo = function(...
syntax in JavaScript despite no mention of "prototype" in the TypeScript code.π» Use Cases
The primary use-case is as described above: immutable types being able to correctly set optional properties optionally without compromising strictness. In addition, this would also be a useful syntactic sugar for mutable use-cases, particularly when
exactOptionalPropertyTypes
is set, avoiding the verbosity of a bunch of if statements.Alternative proposal
Here's another possible syntax that could solve the same problem, but with a bit more expressive power:
This alternative syntax is a bit quirkier, but it has the advantage of not treating
undefined
as a special value.undefined
seems to be the primary use-case here, especially afterexactOptionalPropertyTypes
, but some users may want to have more flexibility to customize this behavior (eg. for the corner case that a property is defined asfoo?: string|undefined
).The text was updated successfully, but these errors were encountered: