有什么方法可以在 TypeScript 中定位普通的 JavaScript 对象类型吗?
Is there any way to target the plain JavaScript object type in TypeScript?
2021 年更新
对于使用较新功能的有效解决方案,请参阅此答案
我正在尝试编写一个函数,我想在其中指明它 return 是 某种 普通 JavaScript 对象。该对象的签名是未知的,目前并不有趣,只是因为它是一个普通对象。我的意思是满足例如 jQuery 的 isPlainObject
功能的普通对象。例如
{ a: 1, b: "b" }
是普通对象,但是
var obj = new MyClass();
不是“普通”对象,因为它的 constructor
不是 Object
。 jQuery 在 $.isPlainObject
中做了一些更精确的工作,但这超出了问题的范围。
如果我尝试使用 Object
类型,那么它将与任何自定义对象兼容,因为它们是从 Object
.
继承的
有没有办法在 TypeScript 中定位“普通对象”类型?
我想要一个类型,例如满足这个。
var obj: PlainObject = { a: 1 }; // perfect
var obj2: PlainObject = new MyClass(); // compile-error: not a plain object
用例
我有一种用于服务器端方法的强类型存根,如下所示。这些存根是由我的一个代码生成器生成的,基于 ASP.NET MVC 控制器。
export class MyController {
...
static GetResult(id: number): JQueryPromise<PlainObject> {
return $.post("mycontroller/getresult", ...);
}
...
}
现在当我在消费者中调用它时 class,我可以做这样的事情。
export class MyViewModelClass {
...
LoadResult(id: number): JQueryPromise<MyControllerResult> { // note the MyControllerResult strong typing here
return MyController.GetResult(id).then(plainResult => new MyControllerResult(plainResult));
}
...
}
现在想象控制器方法 returns JQueryPromise<any>
或 JQueryPromise<Object>
。现在还想象一下,我不小心写了 done
而不是 then
。现在我有一个隐藏的错误,因为 viewmodel 方法不会 return 正确的承诺,但我不会得到编译错误。
如果我有这个假想的 PlainObject
类型,我希望得到一个编译错误,指出 PlainObject
不能转换为 MyControllerResult
,或类似的东西。
在我的代码中,我有一些类似于您所问的内容:
export type PlainObject = { [name: string]: any }
export type PlainObjectOf<T> = { [name: string]: T }
而且我还有一个类型保护:
export function isPlainObject(obj: any): obj is PlainObject {
return obj && obj.constructor === Object || false;
}
编辑
好的,我明白你在找什么,但很遗憾,这是不可能的。
如果我对你的理解正确,那么这就是你想要的:
type PlainObject = {
constructor: ObjectConstructor;
[name: string]: any
}
问题是在 'lib.d.ts' 中 Object 是这样定义的:
interface Object {
/** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
constructor: Function;
...
}
然后是这个:
let o: PlainObject = { key: "value" };
有错误的结果:
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'.
在 TypeScript 3.7.2 中测试:
对于平面物体,你可以这样做:
type Primitive =
| bigint
| boolean
| null
| number
| string
| symbol
| undefined;
type PlainObject = Record<string, Primitive>;
class MyClass {
//
}
const obj1: PlainObject = { a: 1 }; // Works
const obj2: PlainObject = new MyClass(); // Error
对于嵌套的普通对象:
type Primitive =
| bigint
| boolean
| null
| number
| string
| symbol
| undefined;
type JSONValue = Primitive | JSONObject | JSONArray;
interface JSONObject {
[key: string]: JSONValue;
}
interface JSONArray extends Array<JSONValue> { }
const obj3: JSONObject = { a: 1 }; // Works
const obj4: JSONObject = new MyClass(); // Error
const obj5: JSONObject = { a: { b: 1 } }; // Works
const obj6: JSONObject = { a: { b: { c: 1 } } }; // Works
const obj7: JSONObject = { a: { b: { c: { d: 1 } } } }; // Works
代码改编自https://github.com/microsoft/TypeScript/issues/3496#issuecomment-128553540
你可以尝试递归类型(天真的解决方案)
type SerializableObject = { [x: string]: SerializableObject | number | string | [] };
不好,也不差:)
2021 年更新
对于使用较新功能的有效解决方案,请参阅此答案
我正在尝试编写一个函数,我想在其中指明它 return 是 某种 普通 JavaScript 对象。该对象的签名是未知的,目前并不有趣,只是因为它是一个普通对象。我的意思是满足例如 jQuery 的 isPlainObject
功能的普通对象。例如
{ a: 1, b: "b" }
是普通对象,但是
var obj = new MyClass();
不是“普通”对象,因为它的 constructor
不是 Object
。 jQuery 在 $.isPlainObject
中做了一些更精确的工作,但这超出了问题的范围。
如果我尝试使用 Object
类型,那么它将与任何自定义对象兼容,因为它们是从 Object
.
有没有办法在 TypeScript 中定位“普通对象”类型?
我想要一个类型,例如满足这个。
var obj: PlainObject = { a: 1 }; // perfect
var obj2: PlainObject = new MyClass(); // compile-error: not a plain object
用例
我有一种用于服务器端方法的强类型存根,如下所示。这些存根是由我的一个代码生成器生成的,基于 ASP.NET MVC 控制器。
export class MyController {
...
static GetResult(id: number): JQueryPromise<PlainObject> {
return $.post("mycontroller/getresult", ...);
}
...
}
现在当我在消费者中调用它时 class,我可以做这样的事情。
export class MyViewModelClass {
...
LoadResult(id: number): JQueryPromise<MyControllerResult> { // note the MyControllerResult strong typing here
return MyController.GetResult(id).then(plainResult => new MyControllerResult(plainResult));
}
...
}
现在想象控制器方法 returns JQueryPromise<any>
或 JQueryPromise<Object>
。现在还想象一下,我不小心写了 done
而不是 then
。现在我有一个隐藏的错误,因为 viewmodel 方法不会 return 正确的承诺,但我不会得到编译错误。
如果我有这个假想的 PlainObject
类型,我希望得到一个编译错误,指出 PlainObject
不能转换为 MyControllerResult
,或类似的东西。
在我的代码中,我有一些类似于您所问的内容:
export type PlainObject = { [name: string]: any }
export type PlainObjectOf<T> = { [name: string]: T }
而且我还有一个类型保护:
export function isPlainObject(obj: any): obj is PlainObject {
return obj && obj.constructor === Object || false;
}
编辑
好的,我明白你在找什么,但很遗憾,这是不可能的。
如果我对你的理解正确,那么这就是你想要的:
type PlainObject = {
constructor: ObjectConstructor;
[name: string]: any
}
问题是在 'lib.d.ts' 中 Object 是这样定义的:
interface Object {
/** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
constructor: Function;
...
}
然后是这个:
let o: PlainObject = { key: "value" };
有错误的结果:
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'.
在 TypeScript 3.7.2 中测试:
对于平面物体,你可以这样做:
type Primitive =
| bigint
| boolean
| null
| number
| string
| symbol
| undefined;
type PlainObject = Record<string, Primitive>;
class MyClass {
//
}
const obj1: PlainObject = { a: 1 }; // Works
const obj2: PlainObject = new MyClass(); // Error
对于嵌套的普通对象:
type Primitive =
| bigint
| boolean
| null
| number
| string
| symbol
| undefined;
type JSONValue = Primitive | JSONObject | JSONArray;
interface JSONObject {
[key: string]: JSONValue;
}
interface JSONArray extends Array<JSONValue> { }
const obj3: JSONObject = { a: 1 }; // Works
const obj4: JSONObject = new MyClass(); // Error
const obj5: JSONObject = { a: { b: 1 } }; // Works
const obj6: JSONObject = { a: { b: { c: 1 } } }; // Works
const obj7: JSONObject = { a: { b: { c: { d: 1 } } } }; // Works
代码改编自https://github.com/microsoft/TypeScript/issues/3496#issuecomment-128553540
你可以尝试递归类型(天真的解决方案)
type SerializableObject = { [x: string]: SerializableObject | number | string | [] };
不好,也不差:)