Maurizio Vacca Maurizio Vacca - 27 days ago 14
TypeScript Question

Typescript: Property does not exist

I'm trying to develop a decorator for REST Api Interfaces in Typescript. Here it is the decorator implementation

export function RemoteResource(params: any): Function {
console.log("RemoteResource.params: ", params);
return function (target: Function) {

//--POST
target.prototype.post = function () {
console.log("----POST");
};

//--GET
target.prototype.retrieve = function () {
console.log("----GET");
};

//--DELETE
target.prototype.remove = function () {
console.log("----DELETE");
};

//--PULL
target.prototype.update = function () {
console.log("----PULL");
};

console.log("RemoteResource.target: ", target);

return target;
}
}


Now, I can use the decorator
@RemoteResource
and the methods
post|retrieve|remove|update
are added to the original object prototype correctly.

@RemoteResource({
path: "/foos",
methods: [],
requireAuth: false
})
export class Foo { }


From here, if I execute

let tester = new Foo();
tester.post() //--This prints out "----POST" correctly


I've the log printed out correctly, but I've also have the following error: "Property 'post' does not exist on type 'Foo'."
While I understand why I'm having this error (Foo doesn't have any declared
post
property) I'm not sure about how to fix it.

Ideally, I would like that the TS compiler understand that the decorator extends the original object adding up those methods.

How can I achieve it? Any ideas?

Thanks!

Answer

Since you are adding these methods dynamically at runtime in the decorator, the compiler has no way of knowing that these methods will exist for Foo instances.

You can change that in different ways, for example:

(1) Using an interface and intersection:

interface RemoteResource {
    post(): void;
    remove(): void;
    update(): void;
    retrieve(): void;
}

let tester = new Foo() as Foo & RemoteResource;
tester.post(); // no error

(2) Interface and empty methods:

export class Foo implements RemoteResource {
    post: () => void;
    remove: () => void;
    update: () => void;
    retrieve: () => void;
}

let tester = new Foo() as Foo & RemoteResource;
tester.post();

Edit

@Robba suggests:

(3) Ignore all type checking

let tester = new Foo() as any;
tester.post();

or

let tester = new Foo();
tester["post"]();