Repository navigation
Object property in anonymous function in typeguard: Should the typeguard work when the object is const and property is readonly? #9511
Description
Activity
only true for x.a being a primitive (string, number, boolean, null, undefined) won't work for arrays and objects, Date, Refex
sandersn commented
on Jul 28, 2016 MemberMore actionsAleksey-Bykov what can change with non-primitives? For example,
interface I { p: string | undefined; q: number; } const x: { readonly a: I | undefined } = { a: { p: undefined, q: 12 } }; let f: () => number; if (typeof x.a !== 'undefined') { f = () => x.a.q; }
How can I change
x.ato make the property accessx.a.qinvalid?sandersn commented
on Jul 28, 2016 MemberMore actionsFix is up for review at #10015.
Nathan Shively-Sanders (@sandersn) :
const x = { get foo(): {x: number, y: number} | undefined { return this._foo; }, setFoo(foo: any) { this._foo = foo; } }; x.setFoo({x: 42, y: 42}); if (typeof x.foo !== "undefined") { setTimeout(() => console.log(Math.sqrt((x.foo.x ** 2) + (x.foo.y **2))); } x.setFoo(undefined);
Since getters with an unpaired setter are
readonly, no further annotations are required.readonlyisn't the same thing as immutable, and conflating the two could cause issues (beyond the aliasing ones we've already discussed).On the other hand, it was always possibly to write a getter which deleted its own value on access and pass that around pretending it was a plain old object, thereby invalidating any type guards on it; so maybe getters are just awful and don't really matter.
I'm not 100% sure about this change.
readonlyjust means that you can't assign to the property, but there is no guarantee that consecutive get operations will return the same value.checkIdentifieralready usesisReadonlySymbolto decide whether to narrow outside the lambda. Is that incorrect? I guessed that it was allowed because getters were kind of holey and we decided to be less strict (and less correct) in this case.(as a reminder,
isReadonlySymbolincludesreadonly,const,get-only accessors and enum members).- modified the milestones: TypeScript 2.1, This milestone has been deleted, This milestone has been deleted
on Oct 27, 2016 - addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bugand removedBugA bug in TypeScriptA bug in TypeScript
on Sep 17, 2018 Closing per our decision in the design meeting.
- locked as resolved and limited conversation to collaborators
on Oct 22, 2025
TypeScript Version: 2.0.0-dev.20160704
Code
Expected behavior:
x.a.lengthshould be valid, since x.a is in a typeguard, x is constant, and x.a is readonly, and thus value of x.a cannot change even when the function is called at a later time.Actual behavior:
[ts] Object is possibly 'undefined'.
(property) a: string | undefined