Alexander Cerutti
Alexander Cerutti

Reputation: 398

Allow arbitrary properties in class Typescript types

I've created a generic class in Typescript to extend objects starting from one passed in the constructor (through a Proxy, which will be returned in the constructor).

class MyClass<T> {
    private _a: 5;
    constructor(source: T) {
        ...
        return new Proxy(Object.assign(this, source), { ... });
    }
}

If I want to instance MyClass, I'll do:

interface DeepObject {
    a: number,
    b: {
         c: number,
         d: { ... }
    }
}

const x = new MyClass<DeepObject>({
    a: 1,
    b: {
        c: 2,
        d: { ... }
    }
});

So, as result, I will get x as a class that has inside "DeepObject" properties, like a, b, b.d. But if I try to access to x.b.d, it will obliviously not recognize the new properties as they get pushed inside in runtime at the current state. Is there a way to use MyClass's T parameter as a class return type, knowing that I'm returning an edited "this" (MyClass + new props)? I tried to set it to the constructor but typescript doesn't let me, like

    constructor(source: T): ThisType<MyClass<T>> & T { ... }
    constructor(source: T): MyClass<T> & T { ... }

Moreover, using //@ts-ignore in multiple lines (like

//@ts-ignore
x.b.c = 5;
//@ts-ignore
x.b.d.f = 9;

), is a misusage of typescript features, IMHO.

The same is to put [key: string]: any inside the class, above or below the properties.

Thank you very much!

Upvotes: 3

Views: 806

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249466

You can't directly charge the return type of the constructor. You can however use the same approach as Proxy usses and have a separate declaration for the constructor which does use the generic type parameter in the return

class _MyClass<T> {
    private _a: 5;
    constructor(source: T) {

        return new Proxy(Object.assign(this, source), { ... });
    }
}

interface DeepObject {
    a: number,
    b: {
        c: number,
        d: {  }
    }
}
const MyClass : {
    new<T> (s:T) : _MyClass<T> & T
} = _MyClass as any
const x = new MyClass<DeepObject>({
    a: 1,
    b: {
        c: 2,
        d: {  }
    }
});

x.b.c

Upvotes: 1

Related Questions