Skip to content

After updating to 3.x.x getting TS2536  #28647

Closed

Description

TypeScript Version: typescript@3.3.0-dev.20181122

Search Terms:
TS2536 Record Map vuex

Code

interface ITest {
  expectedStr: string;
  expectedN: number;
}

interface MapAccessor<Getters> {
  <T = Getters, Map extends Record<string, keyof T> = Record<string, keyof T>>(
    map: Map
  ): { [K in keyof Map]: (() => T[Map[K]]) };
}

interface TestAccess {
  str: "expectedStr";
}

const t: MapAccessor<ITest> = {} as any;

const str = t({
  str: "expectedStr"
}).str;

Expected behavior:
No compile issue, is working using typescript@3.0.1, checked the breaking changes and found nothing in regards to this.

Intellisense still works as expected giving error if you change expectedStr to an invalid value.

Actual behavior:
Not giving error: index.ts:9:33 - error TS2536: Type 'Map[K]' cannot be used to index type 'T'.

Playground Link:
playground

Activity

  1. jack-williams commented on Nov 22, 2018

    @jack-williams
    Collaborator

    This might be affected by this: #27490 (and thus working as intended).

    Map[K] is no longer pulling in the constraint keyof T because both Map and K are generic.

    I'd wait on a final say from someone on the team though,

  2. pikax commented on Nov 23, 2018

    @pikax
    Author

    What I find odd is the intellisense/editor picking up the correct value.

    Is there a way to have the same behavior without the error?

  3. jack-williams commented on Nov 23, 2018

    @jack-williams
    Collaborator

    Is your editor using an older version of tsserver?

  4. pikax commented on Nov 23, 2018

    @pikax
    Author

    I'm using VSCode and even the typescript playground it works (even with the error it resolves the correct type).

    image

    playground

    EDIT:
    image

  5. weswigham commented on Nov 26, 2018

    @weswigham
    Member

    I think Jack Williams (@jack-williams) is right; but I'm unsure if we wanted this specific kind of pattern to break

  6. ahejlsberg commented on Nov 26, 2018

    @ahejlsberg
    Member

    This is working as intended. A simplified example:

    function f1<T, U extends Record<string, keyof T>, K extends keyof U>(obj: T, map: U, key: K) {
        return obj[map[key]];  // Error
    }

    Here, U is constrained to an object type where properties with string names are constrained to keyof T. However, it is possible for an instantiation to supply a type argument for U that has properties with symbol names which aren't constrained in any way. Therefore U[K] isn't known to be constrained to keyof T.

    Changing the constraint of U to an object type where all properties are constrained to keyof T does indeed work:

    function f2<T, U extends Record<keyof U, keyof T>, K extends keyof U>(obj: T, map: U, key: K) {
        return obj[map[key]];  // Ok
    }
  7. added
    Working as IntendedThe behavior described is the intended behavior; this is not a bug
    and removed
    Domain: Indexed Access TypesThe issue relates to accessing subtypes via index access
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Nov 26, 2018
  8. jack-williams commented on Nov 26, 2018

    @jack-williams
    Collaborator

    Yep, so it seems like I was completely wrong on this one. The mistake I made was that the PR I linked to only concerned the case when relating to an indexed access type; this example is about relating from an indexed access type. Subtle, but wrong. Sorry!

  9. weswigham commented on Nov 26, 2018

    @weswigham
    Member

    cc Daniel Rosenwasser (@DanielRosenwasser) to double-check that we're documenting this break in the 3.2 (? I think that's the first) release.

  10. typescript-bot commented on Dec 13, 2018

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  11. pikax commented on Feb 14, 2019

    @pikax
    Author

    Sorry to comment on a closed issue, is this suppose to happen:

    interface MyGetter {
        vstring : string,
        vnumber: number,
    
        vhidden: boolean;
    }
    declare interface TestGeneric<Getters> {
        <Map extends Record<string, keyof Getters>>(map: Map) : { [K in keyof Map]: Getters[Map[K]]}; 
    }
    
    declare interface TestSpecific {
        <Map extends Record<string, keyof MyGetter>>(map: Map): { [K in keyof Map]: MyGetter[Map[K]]}
    }
    
    declare const genericInterface: TestGeneric<MyGetter>;
    declare const speficInterface: TestSpecific;
    
    const generic = genericInterface({
        testString: 'vstring',
        testNumber: 'vnumber'
    });
    const specific = speficInterface({
        testString: 'vstring',
        testNumber: 'vnumber'
    }); 
    
    
    generic.testNumber; //number
    specific.testNumber; // number
    
    generic.testString; // string
    specific.testString; //string

    TestGeneric is getting a compile error but TestSpecific doesn't, shouldn't the type be correct?

    playground

  12. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Breaking ChangeWould introduce errors in existing codeWorking as IntendedThe 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