UPDATE 2021
For a working solution using newer features see this answer https://mcmap.net/q/484640/-is-there-any-way-to-target-the-plain-javascript-object-type-in-typescript
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. – Clavicytheriumpromise
of an AJAX call, and I want to indicate that the promise value is a plain object (parsed byJSON.parse
for example), and not any instance of any class. So I'd use it as an output type, not an input. – Fearnoughtany
, that shouldn't matter. – ClavicytheriumMyControllerResult
still expectsplainResult
to have certain properties, right? Why don't you create a type definition for that? – Overarchextend
), and I don't want to kind of duplicate the layout ofMyControllerResult
. ActuallyMyControllerResult
is aknockoutjs
viewmodel. – Fearnoughtany
object will be a sub class of "a plain object", this type hint, if it existed, won't be able to enforce very much. – Clavicytherium--noImplicitAny
compiler option. Any class or interface that does not explicitly implement the index signature will be rejected by TypeScript, although I believeObject
is one of them (thus you'll need to modify the native type lib). – Tabbieany
in the use-case example code. – Fearnoughtany
half as a pun, and half as a hint that that may be the only real type applicable here. :) – ClavicytheriumMyControllerResult
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. – OverarchObject
. This is a pretty well defined contract in my opinion. See this jsfiddle jsfiddle.net/pyd466tb – FearnoughtObject
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. – Overarch