Skip to content

Some information is lost when working with keyof against type arguments #48989

Closed
@anton-johansson

Description

@anton-johansson

Bug Report

🔎 Search Terms

Hard topic to search for IMO, but I tried phrases like typescript generic interface lose type information and I only found similar issues but not related.

🕗 Version & Regression Information

I was having trouble using version 4.5.5 (that we're currently using), but I could also reproduce it in the latest version available in the playground (4.6.2). I checked versions back to 3.3.3 in the playground and they all reported the same issue.

⏯ Playground Link

Playground link with relevant code

💻 Code

// BEGIN FRAMEWORK STUFF

type ObjectKey<O, T> = {[K in keyof O]: O[K] extends T ? K : never}[keyof O & string];

interface MyInterface {
    myStringValue: string;
    myIntegerValue: number;
}

abstract class AbstractBase<O> {
    constructor(private readonly object: O) {}

    public getValue<T>(fieldName: ObjectKey<O, T>) {
        return this.object[fieldName];
    }
}

// END FRAMEWORK STUFF

// BEGIN IMPLEMENTATION STUFF

class MyType implements MyInterface {
    myStringValue = "";
    myIntegerValue = -1;
}

class MyInterfaceHolder1<I extends MyInterface> extends AbstractBase<MyInterface> {
    constructor(object: I) {
        super(object);
        this.getValue<number>("myIntegerValue");
    }
}
class MyInterfaceHolder2<I extends MyInterface> extends AbstractBase<I> {
    constructor(object: I) {
        super(object);
        this.getValue<number>("myIntegerValue"); // Argument of type 'string' is not assignable to parameter of type 'ObjectKey<I, number>'.(2345)
    }
}

// END IMPLEMENTATION STUFF

const holder1 = new MyInterfaceHolder1<MyType>(new MyType());
const value1 = holder1.getValue<number>("myIntegerValue");

const holder2 = new MyInterfaceHolder1<MyType>(new MyType());
const value2 = holder2.getValue<number>("myIntegerValue");

🙁 Actual behavior

I lose some type information within the super-class when working with a generic argument.

🙂 Expected behavior

I feel like it should be able to maintain type information here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions