GeezerVison is showing github.com — Two level deep indexed access: read works, write fails · Issue #47352 · microsoft/TypeScript
Two level deep indexed access: read works, write fails #47352DescriptionBug Report
Reading from a two level deep Indexed Access type works, but writing gives "Type cannot be used to index".
🔎 Search Terms
- Indexed Access
- Mapped Type
🕗 Version & Regression Information
- This changed between versions 3.3.3 and 3.5.1
⏯ Playground Link
Playground link with relevant code
💻 Code
enum A {
First = "1",
Second = "2"
}
type Values = { [a in A]: { [b: string]: string }}
const values: Values = {} as any;
function test<T extends A>(a: T, b: string) {
const valueA = values[a];
values[a] = valueA;
const valueB = values[a][b]; // indexing Values[T] with string works
values[a][b] = valueB; // => Type 'string' cannot be used to index type 'Values[T]'
}
🙁 Actual behavior
Indexing a type while reading works, while writing fails with the same indexer.
🙂 Expected behavior
Indexed reads and writes both work when using the same indexer. Activityjcalz commented on Jan 9, 2022 I don't see what this has to do with TS4.6 or the linked PR. Your code example has the same behavior in TS4.5 and indeed all the way back to TS 3.5. I assume it's a consequence of #30769. quixot1c commented on Jan 9, 2022 Joe Calzaretta (@jcalz) seems you are right. I previously tested with a different return type for each of the Values with
interface Lookup {
[A.First]: number
[A.Second]: string
}
type Values = { [a in A]: { [b: string]: Lookup[a] }}
This is where 4.6 did come in to play. Simplifying the problem further I must have forgotten to check if it persisted in older versions. Have updated the issue. changed the title [-]TS4.6 Two level deep indexed access of Mapped Type: read works, write fails[/-] [+]Two level deep indexed access of Mapped Type: read works, write fails[/+] on Jan 9, 2022changed the title [-]Two level deep indexed access of Mapped Type: read works, write fails[/-] [+]Two level deep indexed access: read works, write fails[/+] on Jan 9, 2022quixot1c commented on Jan 9, 2022 As Joe Calzaretta (@jcalz) pointed out it does seem related to #30769. In particular the following:
- Given a type variable T with a constraint C, when an indexed access T[K] occurs on the target side of a type relationship, index signatures in C are now ignored. This is because a type argument for T isn't actually required to have an index signature, it is just required to have properties with matching types.
function f3<T extends { [key: string]: any }>(obj: T) {
let foo = obj['foo'];
let bar = obj['bar'];
obj['foo'] = 123; // Error
obj['bar'] = 'x'; // Error
}
If in this case values[a] is typed as Values[T], does that mean that it in effect becomes the T with constraint C that is referred to in above quote from the PR, meaning its index signatures are ignored? RyanCavanaugh commented on Jan 11, 2022 On read you're allowed to fall back to the constraint type, but as noted above this isn't allowed during a write quixot1c commented on Jan 11, 2022 Ryan Cavanaugh (@RyanCavanaugh) I can't say I understand why, that may be way above my pay grade :) But it seems to me
const valueB = values[a][b];
values[a][b] = valueB;
should never fail given no changes in a and b. RyanCavanaugh commented on Jan 11, 2022 To correctly analyze that, the type of valueB would somehow have to encode that it came from the specific indices given by a and b. The type system is generally designed to track sets of values (types), not specific values or variables. locked as resolved and limited conversation to collaborators on Oct 22, 2025
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|