Skip to content

Mapping using distributive object type fails when key is generated in for loop #50147

Closed
@willocho

Description

@willocho

Bug Report

🔎 Search Terms

Mapped index with enum index
typescript dynamic generic type enum loop

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about distributive object types

⏯ Playground Link

Playground link with relevant code

💻 Code

https://www.typescriptlang.org/play?strictPropertyInitialization=false&jsx=0&ts=4.7.4&ssl=60&ssc=2&pln=27&pc=1#code/KYOwrgtgBAygLgQzsACgJwPYAdhrgTygG8AoKcqAQQCEYoBeKAIhpiYBoyKARAUQDEGzPvw5dyAeQBGAK2ABjOEKYTqAKV4BhACpMSAXxIkCOWImTpsuAgFkEWLAEsQAcyGkKUANpZMOPITOZkioftb4ALoAXFAAqgDOwPGU2vg4ADwIIPgAfAZG8gA2CPHxUKk4dg7OLprFpVCOEFiFwBCgcGXwIZb+tvZOrsTi3t0WYQEAdKzRcYnJFcDpUhgYrVk5ANwjXmOhVlMiswlJKWlL4BBSuFs7e73hk9JyisfzZxlECDGX12ibUCkMRWa2AWX0t0MJCKJTKJwW53S2hyHgoWDAUkKjnkUAAJsAAGYIMCFOAANQQhTAwBi2m2UJhDXhiyqgxc6QA0sBCMAAB7IEC4rrmfZ9XKo8jozHYqAAa25MS5+G2nilWJxADdKdTaedWTU6rCvEqIl4AOT4okk8na4BmiIqtEY9VQRDy+IUqnAIQACg1usqAwN9Xixu5pothOJpM91PtAEoGDliGhgHAwGgQFANfp6UYAPT57iE5yOOCODBZgCMJELcxqroAFo4ypbS+XK1AXI4NUkoFkoLhMGgm0hguMDgQoPIsmalNcoGBErjXRhGoK+VAqsy9UHXLX867zlv7PEd4HqkNGKQ6xQvPLAln7hMCG8kiy9+yH3k6-pdiKHgCCICyLEsQDLCsswAJgPBIGzgZtWzAiDO27XsygHLAEDQBB2mQEc4DXN0kljb0WygEAMCUWFHBcEAEExb1CIo4BezQYxjyqM95g-S83GvHYH3XcdRXCN94l4tl0m-fJoRDKAAHUy0bKpKHiGw2j+YZVWdGUIHsDSrlwGIuPPYB9VcbYRnkSt4jgNAwEUDA0B9fSsEMv4TNPMyLJcRMJU8JsW0mNyPNwIRQs03BHXIKEdOlHEEJbAB9IlHEKeIfXjALPAJZyfVaJQyiCZ9J3wbKRkCihC14NBhygDB5HkDMykbXBgEqqqgviEKDKitAvAw4UehfSJJmIj1bR9JKesioyBqGkTANfSYtS9eNOtikY4qdBLuuSgB3ZzZXiQ7lOSmc7JqLKcooPKXMKqBiqfADRoqrrAsepRGEW0qxRij6oELbREKgI60BOzbAp9dIfM-dITGADACVdHIchm3r3P6rw4AieNxoQd1SOmxDMbCgbcdW20No+wxPEMfQgA

//Enum
enum StateProperty {
    ABS = "ABS",
    DEF = "DEF",
    Object = "OBJECT"
}

//Type definition for mapping type
type StatePropertyMapping = {
    [property in StateProperty]: UsesAType<any>
}

//Actual type mappings
class TypeMappingClass implements StatePropertyMapping {
    [StateProperty.ABS]: UsesAType<boolean>;
    [StateProperty.DEF]: UsesAType<number>;
    [StateProperty.Object]: UsesAType<{a: number; b: boolean}>;
}

class UsesAType<T>{
    public defaultValue: T;
}

class UsesTypeMapping<Key extends StateProperty>{
    public key: Key;
    public value: TypeMappingClass[Key]['defaultValue']; //This is a separate class that wants to know the type mapping for 'Key'
    public takesValue = (v: TypeMappingClass[Key]['defaultValue']) => {return v};
}

//Definition 1
// Using this definition gives an error that 'StateProperty can't be used to index MapUsesTypeMapping'
// type MapsUsesTypeMapping = {
//    [key in StateProperty]: UsesTypeMapping<key>
// }[StateProperty]

//Definition 2
//Using this definition gives an error that 'parameter to takesValue is not assignable to never'
type MapsUsesTypeMapping = {
    [key in StateProperty]: UsesTypeMapping<key>
}

class WithMapAsMember {
    public mapMember: MapsUsesTypeMapping;

    constructor(mapMember: MapsUsesTypeMapping) {
        this.mapMember = mapMember;
    }

    public this_fails(){
        for(let s in StateProperty){
            //Error occurs here
            this.mapMember[s as StateProperty].takesValue(this.mapMember[s as StateProperty].value)
        }
    }

    public this_works_with_casting(){
        for(let s in StateProperty){
            let t = s as StateProperty;
            //This works with definition 2 only
            (<UsesTypeMapping<typeof t>>this.mapMember[t]).takesValue(this.mapMember[t].value)
        }
    }
}

🙁 Actual behavior

If I try to setup the mapping using an enum, the compiler is unable to infer the type mapping based of the union type when the value is generated at runtime (i.e. in a loop)

🙂 Expected behavior

I expect that the compiler will be able to infer the type that takesValue accepts when mapMember is indexed using a specific state property, similar to how it is described in this issue: #47109

Metadata

Metadata

Assignees

No one assigned

    Labels

    UnactionableThere isn't something we can do with this issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions