Description
I understand the use of type widening with let
and var
variables (I use const
ubiquitously so this is never a problem). But with object literals I pretty much never want the fields to be widened, and yet that's the default behavior:
const o = { x: 3 }; // inferred type is { x: number }
The only way I know of to work around this is with casts or type annotations, or by passing the object literal immediately to a function expecting the narrower type, thereby guiding type inference (although if the literal is being returned from a function even that technique won't work).
This is an eternal headache and it crops up in so many places. Would it be possible to add a compiler flag that makes it so that object literals don't get widened? I'm happy to be responsible for adding type annotations in the extremely rare cases where I actually want the widened type.
Edit
It looks like compiler flags are generally frowned upon to solve this problem, so let me amend my suggestion to take account of the discussion below. @mhegazy says,
We have talked in the past about a
readonly
modifier on property declarations.. e.g.const o = { readonly x: 3 };this allows the compiler to understand the intent of this object literal property, and not widen.
This would certainly be handy, but on its own it's still not ideal because one ends up writing readonly
in a lot of places. Take for example CSS-in-JS objects, which involve many properties whose types are unions of string literals. Every single one of those properties needs to then be marked readonly
in order to defeat the scourge of type widening. But if one could declare an entire object literal to have only read-only properties like so:
const o = readonly { x: 3, y: 'hello' };
// o: { readonly x: 3; readonly y: 'hello' }
now this starts to look like a workable solution! So, let this be my amended suggestion: readonly
modifiers for both object literal properties as well as object literals themselves, which has the side effect of disabling type widening.
To the argument that readonly
and type-widening are separate concerns and should be treated independently, to some extent I agree, but I also feel they are related; this is why the let
vs. const
rules for type widening exist, and I think that rationale makes sense. I also personally don't mind conflating readonly
and type narrowing, because I prefer immutable objects everywhere too, so a syntax like
const o = readonly { x: 3, y: 'hello' };
would be attractive because it kills 2 birds with one stone. I currently don't use the readonly
keyword much (even though in spirit I want everything to be read-only) because the cost-benefit ratio of annotating every single property in every single object literal is too high.