问题
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.
回答1:
In my code I have something similiar to what you're asking:
export type PlainObject = { [name: string]: any }
export type PlainObjectOf<T> = { [name: string]: T }
And I also have a type guard for that:
export function isPlainObject(obj: any): obj is PlainObject {
return obj && obj.constructor === Object || false;
}
Edit
Ok, I understand what you're looking for, but unfortunately that is not possible.
If i understand you correctly then this is what you're after:
type PlainObject = {
constructor: ObjectConstructor;
[name: string]: any
}
The problem is that in 'lib.d.ts' Object is defined like so:
interface Object {
/** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
constructor: Function;
...
}
And then this:
let o: PlainObject = { key: "value" };
Results with an error:
Type '{ key: string; }' is not assignable to type 'PlainObject'.
Types of property 'constructor' are incompatible.
Type 'Function' is not assignable to type 'ObjectConstructor'.
Property 'getPrototypeOf' is missing in type 'Function'.
来源:https://stackoverflow.com/questions/42027864/is-there-any-way-to-target-the-plain-javascript-object-type-in-typescript