microsoft/TypeScript

Object literal with variable property is overly generic

xealot opened this issue · 6 comments

Code

interface BV {
    A: string,
    B: number,
}

type BVTemplate<K extends keyof BV> = {
    [P in K]?: BV[P];
}

abstract class BaseBlock<T extends keyof BV> {
    abstract readonly typeName: T;
    value: BVTemplate<T>;

    update(v: BV[T]) {
        const updated: BVTemplate<T> = {
            [this.typeName]: v,
        }
        // const updated: BVTemplate<T> = {};
        // updated[this.typeName] = v;

        this.value = updated;
    }
}

Expected behavior:

typeName is T, but the type is incompatible with BVTemplate because the object literal declaration stores it as string. string is not compatible to T.

Actual behavior:

I would hope this example could work. The commented string works perfectly, and in JS land those two things should be equivalent.

The computed property doesn't take the union type - so it is widened to string.

Simplified Example

const a = {} as "FOO" | "BAR";

const o = {
    [a]: true
};

// type of o is {  [x: string]: boolean; }

Should be addressed by #21070

After some discussion with @mhegazy, we decided that this issue is a job for the proposed Unionize type. It is not fixed by #21070 in any case.

here is the sample using the unionize type:

class BaseBlock<T extends keyof BV> {
    readonly typeNameT;
    valueBVTemplate<T>;

    update(vBV[T]) {
       type union = {[P in T]{[Q in P]typeof v } }[T];

       const updatedBVTemplate<T> = {
           [this.typeName]v,
       } as union;
       this.value = updated;
    }
} 

more discussion in #18155

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.