GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

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 #47352

New issue
Copy link
New issue
Copy link
Closed
Closed
Two level deep indexed access: read works, write fails#47352
Copy link
Labels
Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug

Description

@quixot1c
quixot1c
opened on Jan 8, 2022
Issue body actions

Bug 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.

Activity

  1. jcalz commented on Jan 9, 2022

    @jcalz
    Joe Calzaretta (jcalz)
    on Jan 9, 2022
    Contributor
    More actions

    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.

  2. quixot1c commented on Jan 9, 2022

    @quixot1c
    quixot1c
    on Jan 9, 2022
    Author
    More actions

    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.

  3. quixot1c
    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, 2022
  4. quixot1c
    changed 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, 2022
  5. quixot1c commented on Jan 9, 2022

    @quixot1c
    quixot1c
    on Jan 9, 2022
    Author
    More actions

    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?

  6. Ryan Cavanaugh (RyanCavanaugh)
    added
    Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
    on Jan 11, 2022
  7. RyanCavanaugh commented on Jan 11, 2022

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Jan 11, 2022
    Member
    More actions

    On read you're allowed to fall back to the constraint type, but as noted above this isn't allowed during a write

  8. quixot1c commented on Jan 11, 2022

    @quixot1c
    quixot1c
    on Jan 11, 2022
    Author
    More actions

    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.

  9. RyanCavanaugh commented on Jan 11, 2022

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Jan 11, 2022
    Member
    More actions

    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.

  10. quixot1c
    closed this as completedon Jan 11, 2022
  11. microsoft
    locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.