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.
Tested in TypeScript 3.7.2:
For a flat plain object, you can do:
For a nested plain object:
Code is an adaptation from https://github.com/microsoft/TypeScript/issues/3496#issuecomment-128553540
For primitives, see mdn web docs > Primitive.
An alternative solution would be to use a library sindresorhus / type-fest or use the implementation from it found here: https://github.com/sindresorhus/type-fest/blob/main/source/basic.d.ts.