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. ghost added
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Nov 26, 2018
  6. ghost added
    Domain: Indexed Access TypesThe issue relates to accessing subtypes via index access
    on Nov 26, 2018
  7. ghost
    self-assigned this
    on Nov 26, 2018
  8. weswigham commented on Nov 26, 2018

    @weswigham
    Member

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

  9. 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
    }
  10. ghost added
    Working as IntendedThe behavior described is the intended behavior; this is not a bug
    on Nov 26, 2018
  11. ghost removed
    Domain: Indexed Access TypesThe issue relates to accessing subtypes via index access
    on Nov 26, 2018
  12. ghost removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Nov 26, 2018
  13. 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!

  14. ghost added
    Breaking ChangeWould introduce errors in existing code
    on Nov 26, 2018
  15. weswigham commented on Nov 26, 2018

    @weswigham
    Member

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

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

  17. ghost closed this as completedon Dec 13, 2018
  18. 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

  19. ghost 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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions