0

I'm trying to add types to a class which extends "this" in the constructor.
I saw this question Typescript: extending "this" inside class but I don't know in advance which object would passed to the constructor.

class Baz<T extends object> {
    public test;
    constructor(props: T) {
        Object.assign(this, props);
    }
}

interface IFoo {
  foo: number;
}

const p = new Baz<IFoo>({foo: 1});
p.test;
p.foo; // Not recognized.

I'm trying to recognize as properties the fields passed as object.

2
  • Please ensure you share code that only has errors related to your actual question. You're missing a type and an initializer on test. Commented Dec 28, 2022 at 14:15
  • You are right. In fact test wasn't really relevant... It was there just to show that I can access to the property of the class (of course) but not the one assigned in the constructor (foo) Commented Dec 28, 2022 at 14:55

1 Answer 1

1

I don't think you can do this with a constructor and a generic class. You could use a generic type parameter on the class to affect the type of a data member or a method's argument or return type, but not to add features to the class itself.

You can do it with a static method, though (or just a standalone function):

class Baz {
    public test: string = "something";

    private constructor() { // If you want it to be private; that's up to you
    }

    static create<T extends object>(props: T): Baz & T {
        const b = new Baz();
        Object.assign(b, props);
        return b as Baz & T;
    }
}

interface IFoo {
    foo: number;
}

const p = Baz.create<IFoo>({ foo: 1 });
p.test;
p.foo; // <== Works fine

Playground example

Sign up to request clarification or add additional context in comments.

2 Comments

I'm adding types to an existing javascript codebase. So the only way is to change the code? I find it a bit unfortunate...
@user2342561 - Certain patterns people have used in JavaScript don't map well to TypeScript's type system. I'm fairly sure this is one of them. IMHO, what was there was already off semantically -- the code says new Baz but what you get back isn't a Baz, it's a Baz + ____. I don't think TypeScript has a way to express that using a constructor. So yeah, you either have to change the code or use a type assertion everywhere you were doing it (new Baz(/*...*/) as Baz & ____), which seems like more work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.