UPDATE 2021
For a working solution using newer features see this answer https://stackoverflow.com/a/59647842/1323504
I'm trying to write a function where I'd like to indicate that it returns some kind of plain JavaScript object. The object's signature is unknown, and not interesting for now, only the fact that it's a plain object. I mean a plain object which satisfies for example jQuery's isPlainObject
function. For example
{ a: 1, b: "b" }
is a plain object, but
var obj = new MyClass();
is not a "plain" object, as its constructor
is not Object
. jQuery does some more precise job in $.isPlainObject
, but that's out of the question's scope.
If I try to use Object
type, then it will be compatible to any custom object's too, as they're inherited from Object
.
Is there a way to target the "plain object" type in TypeScript?
I would like a type, which would satisfy this for example.
var obj: PlainObject = { a: 1 }; // perfect
var obj2: PlainObject = new MyClass(); // compile-error: not a plain object
Use case
I have kind of a strongly-typed stub for server-side methods, like this. These stubs are generated by one of my code generators, based on ASP.NET MVC controllers.
export class MyController {
...
static GetResult(id: number): JQueryPromise<PlainObject> {
return $.post("mycontroller/getresult", ...);
}
...
}
Now when I call it in a consumer class, I can do something like this.
export class MyViewModelClass {
...
LoadResult(id: number): JQueryPromise<MyControllerResult> { // note the MyControllerResult strong typing here
return MyController.GetResult(id).then(plainResult => new MyControllerResult(plainResult));
}
...
}
And now imagine that the controller method returns JQueryPromise<any>
or JQueryPromise<Object>
. And now also imagine that by accident I write done
instead of then
. Now I have a hidden error, because the viewmodel method will not return the correct promise, but I won't get a compile-error.
If I had this imaginary PlainObject
type, I'd expect to get a compile error stating that PlainObject
cannot be converted to MyControllerResult
, or something like that.
any
value, since pretty much everything in Javascript is an object and you don't even care about any specific characteristics of it. The caller of your function may decide to implement your desired object as a class for their own purposes; the resulting object will still be perfectly compatible with your expected "plain" object, especially if you don't even really care about anything about that object. While an interesting question, I somewhat fail to see the practicality of it.any
, that shouldn't matter.MyControllerResult
requires the object to have some specific properties, you should document those then use that as your type. I fail to see howPlainObject
is useful here.Object
but that doesn't tell you anything about the kind of data you're expecting. Please explain to me why defining your contract based on the kind of data you're going to receive (i.e., what properties you expect the object to have) is a bad idea. Right now it seems like you're just focused on applying your flawed idea rather than correcting your approach.