You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Confusing error message (2322), should use (2741) and (2322) error message when this["XXX"] = {...} has a missing (or mispelled) key or an incompatible value. #63206
When we have a Record this["faa"] to which we affect an object with an incompatible type, e.g.:
a key is missing (or misspelled).
one value has the wrong type.
The following error is shown:
Type '{}' is not assignable to type 'this["faa"]'.
'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{}'.(2322)
input.tsx(3, 19): 'key' is declared here.
In this context, I'd like the error message to be modified in order to be less confusing, i.e. :
if a key is missing: "Property 'key' is missing in type '{}' but required in type '{ key: number | null; }'.(2741)"
if one value has a wrong type: "Type 'string' is not assignable to type 'number'.(2322)".
classA{declarefoo: this["faa"];declarefaa: {key: number|null}fuu(){// Type '{}' is not assignable to type 'this["faa"]'.// 'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{}'.(2322)// input.tsx(3, 19): 'key' is declared here.this.foo={}// Type '{ key: string; }' is not assignable to type 'this["faa"]'.// 'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{ key: string; }'.(2322)this.foo={key: "str"}this.foo={key: 42}// ok}}letfoo: {key: number|null};// Property 'key' is missing in type '{}' but required in type '{ key: number | null; }'.(2741)// input.tsx(12, 11): 'key' is declared here.foo={}// Type 'string' is not assignable to type 'number'.(2322)// input.tsx(12, 11): The expected type comes from property 'key' which is declared here on type '{ key: number | null; }'foo={key: "str"}foo={key: 42}// ok
It is easy to forget a key or to misspell it. Unfortunately, the error message is currently confusing.
When playing with this["faa"] we often encounter this error, and we might look at it too quickly, missing (or misunderstanding) the last line, thinking this is some kind of TS limitation.
If you are doing subclassing, then this refers to an unresolved generic type, and a subclass S of A could have a different type for S["faa"]. The current error messages are correct in that case; it really is a constraint problem, and the compiler can't tell you more as the type is unresolved.
Even if the type is unresolved, the compiler is still able to see that something isn't right as shown by:
this.foo={key: 42}// ok
Here, it doesn't detect an error.
When a key is missing, the compiler is still able to know which key is missing, as shown by:
// Type '{}' is not assignable to type 'this["faa"]'.
// 'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{}'.(2322)
// input.tsx(3, 19): 'key' is declared here.
this.foo = {}
The compiler already has the information (as shown by input.tsx(3, 19): 'key' is declared here.) and should therefore be able to tell me that the key is missing.
When one value has an incompatible type, the compiler is able to detect it, as shown by:
// Type '{ key: string; }' is not assignable to type 'this["faa"]'.// 'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{ key: string; }'.(2322)this.foo={key: "str"}
The compiler couldn't raise such error without verifying the type of the value associated to "key".
So it should be able to tell me that this verification failed.
When subclassing, I can indeed redefine this["faa"] by adding a property. But AFAIK, TS doesn't have the syntax to indicate that this["faa"] is an input or output value.
If this is an output value, we can add required properties.
If this is an input value, we should only be able to add optional properties.
this.foo = {key: 42} // no errors
Could also raise an error as a key might be added in the subclasses. But TS doesn't know if this is an input or an ouput value i.e. the the added keys will be optional or required.
In my case this is an output value so subclasses could add required properties.
Still I need to provide the value somewhere, a somewhere that could be overridden by subclasses.
For context, I indeed work with subclasses, with mixins, and have several this[xxx], e.g.
True, when used for the output but not for the input (I distinguish the 2 as it is different usages/constraints).
In this case, TS also raises the 2322 error:
classBextendsA{declarefaa: {key: 5|null}fuu(){// Type '{ key: 42; }' is not assignable to type 'this["faa"]'.// 'this["faa"]' could be instantiated with an arbitrary type which could be unrelated to '{ key: 42; }'.(2322)this.foo={key: 42}}}
It feels like TS assumes this[XXX] to be close to a kind of output value:
required properties can be added.
properties can be specialized.
Still, it indeed accepts this.foo = {key: 42} in the base class, which could cause issues.
A solution would be to have e.g. this.foo = this.generateFoo() but I do not think TS has the syntax or a workaround to indicate : "redefine generateFoo() when this["faa"] changes".
Therefore I do not think this should raise an error for now.
Still, it indeed accepts this.foo = {key: 42} in the base class, which could cause issues.
Yes, this is an intentional unsoundness in the type system.
A solution would be to have e.g. this.foo = this.generateFoo() but I do not think TS has the syntax or a workaround to indicate : "redefine generateFoo() when this["faa"] changes".
That's correct, it does not have such a feature. It probably wouldn't really solve the problem, becasue generateFoo() can already have the return type this["faa"], but then you'd be stuck with the issue of creating a matching object literal again. IMO the only sensible approach for such highly dynamic cases is a type assertion.
Therefore I do not think this should raise an error for now.
The type this is essentially the same as an unbound generic type argument. TypeScript doesn't know what type it exactly is, so it forbids certain features to be used. Your suggestion would apply to the generic cases as well.
classGeneric<Textends{a: number}>{declarefoo: Tfuu(){// Type '{ a: number; }' is not assignable to type 'T'.// '{ a: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ a: number; }'.this.foo={a: 123};}}
Type assertions and the unsound features are escape holes for this.
classA{declarefoo: this["faa"];declarefaa: {key: number|null}fuu(){this.foo={key: 42}// ok, might cause issue when subclassing.}}
In some languages, this would requires this.foo = {key: 42} as this["faa"], in order to explicit:
intent, we know what we are doing ;
the fact that we are doing something a little "dangerous".
So we could make it "sound" by adding an error/warning like:
Type '{ a: number; }' is not assignable to type 'T'.
'{ a: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ a: number; }'.
If this is voluntary, cast the value with 'as T' before assignation.
Does TS has this kind of "principle" ? Requiring developers to explicit intent when doing something correct but potentially dangerous ?
Though:
not sure about the side effects when manipulating complex types.
the cast might remove some checks.
So not a perfect solution.
An alternative, as suggested in other issues, would be to be able to suppress specific errors like Deno is doing, e.g.
I took a look at this and traced the root cause in the checker.
When assigning to an indexed access type like this["faa"], structuredTypeRelatedToWorker correctly resolves the constraint (e.g. {key: number|null}) and performs a structural comparison via isRelatedTo, which generates specific error elaboration (missing properties, type mismatches, etc.). However, in reportRelationError, when the source is not assignable to the constraint, errorInfo is unconditionally set to undefined before reporting the generic "could be instantiated with an arbitrary type" message — discarding all the useful elaboration that was just computed.
The fix is to preserve errorInfo when the target is an IndexedAccess type, so the specific details are retained alongside the generic message.
I'd like to take this one (Confusing error message (2322), should use (2741) and (2322)). I'll look into the root cause and follow up with a PR. (claiming via Stella (@LeonxLJX))
I'd like to take this one (Confusing error message (2322), should use (2741) and (2322)). I'll dig into the root cause and follow up with a PR shortly. (claiming via Stella (@LeonxLJX))
I'd like to take this one (Confusing error message (2322), should use (2741) and (2322)). I'll look into the root cause and follow up with a PR. (claiming via Stella (@LeonxLJX))
Activity
nmain commentedon Mar 2, 2026
If you're not doing any subclassing, replace
with
and everything will work as you'd expect.
If you are doing subclassing, then
thisrefers to an unresolved generic type, and a subclassSofAcould have a different type forS["faa"]. The current error messages are correct in that case; it really is a constraint problem, and the compiler can't tell you more as the type is unresolved.denis-migdal commentedon Mar 3, 2026
This is incorrect.
Even if the type is unresolved, the compiler is still able to see that something isn't right as shown by:
Here, it doesn't detect an error.
When a key is missing, the compiler is still able to know which key is missing, as shown by:
The compiler already has the information (as shown by
input.tsx(3, 19): 'key' is declared here.) and should therefore be able to tell me that the key is missing.When one value has an incompatible type, the compiler is able to detect it, as shown by:
The compiler couldn't raise such error without verifying the type of the value associated to "key".
So it should be able to tell me that this verification failed.
When subclassing, I can indeed redefine
this["faa"]by adding a property. But AFAIK, TS doesn't have the syntax to indicate thatthis["faa"]is an input or output value.If this is an output value, we can add required properties.
If this is an input value, we should only be able to add optional properties.
Could also raise an error as a key might be added in the subclasses. But TS doesn't know if this is an input or an ouput value i.e. the the added keys will be optional or required.
In my case this is an output value so subclasses could add required properties.
Still I need to provide the value somewhere, a somewhere that could be overridden by subclasses.
For context, I indeed work with subclasses, with mixins, and have several
this[xxx], e.g.I also know the trick:
But this would be quite hellish in my system.
denis-migdal commentedon Mar 3, 2026
For information, TS is able to take
this['faa']changes in the subclasses:MartinJohns commentedon Mar 3, 2026
Subclasses can not only add properties, but also provide more specific types:
denis-migdal commentedon Mar 3, 2026
True, when used for the output but not for the input (I distinguish the 2 as it is different usages/constraints).
In this case, TS also raises the 2322 error:
It feels like TS assumes
this[XXX]to be close to a kind of output value:Still, it indeed accepts
this.foo = {key: 42}in the base class, which could cause issues.A solution would be to have e.g.
this.foo = this.generateFoo()but I do not think TS has the syntax or a workaround to indicate : "redefinegenerateFoo()whenthis["faa"]changes".Therefore I do not think this should raise an error for now.
MartinJohns commentedon Mar 3, 2026
Yes, this is an intentional unsoundness in the type system.
That's correct, it does not have such a feature. It probably wouldn't really solve the problem, becasue
generateFoo()can already have the return typethis["faa"], but then you'd be stuck with the issue of creating a matching object literal again. IMO the only sensible approach for such highly dynamic cases is a type assertion.The type
thisis essentially the same as an unbound generic type argument. TypeScript doesn't know what type it exactly is, so it forbids certain features to be used. Your suggestion would apply to the generic cases as well.Type assertions and the unsound features are escape holes for this.
denis-migdal commentedon Mar 3, 2026
TS seems to make the difference between the
this[XXX]case and the generic case asthis.foo = { a: 123 };:this[XXX]case.Couldn't the
this[XXX]case have more explicit messages then ?denis-migdal commentedon Mar 4, 2026
I was thinking about:
In some languages, this would requires
this.foo = {key: 42} as this["faa"], in order to explicit:So we could make it "sound" by adding an error/warning like:
Does TS has this kind of "principle" ? Requiring developers to explicit intent when doing something correct but potentially dangerous ?
Though:
So not a perfect solution.
An alternative, as suggested in other issues, would be to be able to suppress specific errors like Deno is doing, e.g.
// @ts-ignore 2322: documenting the reason here.Preserve error elaboration for indexed access type assignments
WhiteMinds commentedon Mar 21, 2026
I took a look at this and traced the root cause in the checker.
When assigning to an indexed access type like
this["faa"],structuredTypeRelatedToWorkercorrectly resolves the constraint (e.g.{key: number|null}) and performs a structural comparison viaisRelatedTo, which generates specific error elaboration (missing properties, type mismatches, etc.). However, inreportRelationError, when the source is not assignable to the constraint,errorInfois unconditionally set toundefinedbefore reporting the generic "could be instantiated with an arbitrary type" message — discarding all the useful elaboration that was just computed.The fix is to preserve
errorInfowhen the target is anIndexedAccesstype, so the specific details are retained alongside the generic message.PR: #63278
Preserve error elaboration for indexed access type assignments
Preserve error elaboration for indexed access type assignments
Preserve error elaboration for indexed access type assignments
Preserve error elaboration for indexed access type assignments
Preserve error elaboration for indexed access type assignments
Preserve error elaboration for indexed access type assignments
alisa-xh commentedon Apr 14, 2026
LeonxLJX commentedon Sep 1, 2026
I'd like to take this one (
Confusing error message (2322), should use (2741) and (2322)). I'll look into the root cause and follow up with a PR. (claiming via Stella (@LeonxLJX))LeonxLJX commentedon Sep 1, 2026
I'd like to take this one (
Confusing error message (2322), should use (2741) and (2322)). I'll dig into the root cause and follow up with a PR shortly. (claiming via Stella (@LeonxLJX))LeonxLJX commentedon Sep 1, 2026
I'd like to take this one (
Confusing error message (2322), should use (2741) and (2322)). I'll look into the root cause and follow up with a PR. (claiming via Stella (@LeonxLJX))