doctor_haifisch
doctor_haifisch

Reputation: 53

Typescript - Property is missing in type implementing an interface, even though the property is defined

In one of my ts modules, I have an interface defined, with a class that implements it like so (cleaned for brevity):

export interface Encoder {
    name: string;
    exec: (str: string, origParam?: string | null) => string;
}

class NOPEncoder implements Encoder {
    public name: "None";
    public exec(str: string, origParam?: string | null): string {
        // origParam is not important in this case, this method is designed as a no-op
        return str;
    }
}

However, trying to create a Map<string, Encoder> is giving me some problems. I've tried both of these methods of constructing a value of said type:

// Method 1
const encoders = new Map<string, Encoder>();
encoders.set("NOP", NOPEncoder);

// Method 2
const encoders = new Map<string, Encoder> ([
    ["NOP", <Encoder>NOPEncoder],
]);

Both method 1 and method 2 give me an error like "Type 'typeof NOPEncoder' cannot be converted to type 'Encoder'. Property 'exec' is missing in type 'typeof NOPEncoder'." However, the NOPEncoder class explicitly implements the Encoder interface (and the compiler is fine with this), and it clearly has an exec method. What am I doing wrong here such that the compiler doesn't accept that NOPEncoder is coercible into an Encoder instance?

Upvotes: 2

Views: 2109

Answers (1)

wmorrell
wmorrell

Reputation: 5337

NOPEncoder is a class. You are defining the Map as taking an instance of Encoder; i.e. the class NOPEncoder is not an instance of Encoder, it is a type that extends Encoder. This should work:

const encoders = new Map<string, Encoder>();
encoders.set("NOP", NOPEncoder());

If you want to store the actual class reference, I am not currently aware of a way to do this in TypeScript. I would be very interested to learn of a way to do this, if anyone knows!

Edited to add: @jcalz has a close-enough method of storing the signature of the type constructor, as Map<string, new (...args: any[]) => Encoder>. Neat trick, I'll have to play around with it sometime!

Upvotes: 1

Related Questions