繁体   English   中英

有什么方法可以针对 TypeScript 中的普通 JavaScript object 类型吗?

[英]Is there any way to target the plain JavaScript object type in TypeScript?

2021 年更新

对于使用较新功能的有效解决方案,请参阅此答案https://stackoverflow.com/a/59647842/1323504


我正在尝试编写一个 function,我想指出它返回某种普通的JavaScript object。该对象的签名未知,目前并不有趣,只是它是一个普通的 object。我的意思是一个普通的object 满足例如 jQuery 的isPlainObject function。例如

{ a: 1, b: "b" }

是一个普通的 object,但是

var obj = new MyClass();

不是“普通”object,因为它的constructor不是Object jQuery 在$.isPlainObject中做了一些更精确的工作,但这与 scope 无关。

如果我尝试使用Object类型,那么它也将与任何自定义对象兼容,因为它们是从Object继承的。

有没有办法在 TypeScript 中定位“普通对象”类型?

我想要一个type ,它可以满足这个要求。

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));
  }
  ...
}

现在假设 controller 方法返回JQueryPromise<any>JQueryPromise<Object> 现在还想象一下,我不小心写done而不是then 现在我有一个隐藏错误,因为 viewmodel 方法不会返回正确的 promise,但我不会得到编译错误。

如果我有这个虚构PlainObject类型,我希望得到一个编译错误,指出PlainObject无法转换为MyControllerResult或类似的东西。

在 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

在我的代码中,我有一些类似于您要问的内容:

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' 对象是这样定义的:

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'.

您可以尝试递归类型(幼稚的解决方案)

type SerializableObject = { [x: string]: SerializableObject | number | string | [] };

不好,不可怕:)

我发现这适用于 TS 4.9:

type PlainObject = Record<string, {}>;

class MyClass {}

function test(one: PlainObject) {}
test({ a: 1, b: "a", c: new MyClass() }); // OK
test(1); // Error
test("a"); // Error
test([1, 2, 3]); // Error
test(new Date()); // Error
test(new Map()); // Error
test(new Set()); // Error
test(new MyClass()); // Error

TS 游乐场链接

与接受的答案的不同之处在于,它还允许普通 object 包含复杂的值,而不仅仅是基元:

type ObjectOfPrimitives = Record<string, Primitive>;

function test(one: ObjectOfPrimitives) {}

test({ 
  a: 1, 
  b: "a", 
  c: new MyClass(), // Error: Type 'MyClass' is not assignable to type 'ObjectOfPrimitives'.
}); 

TS 游乐场链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM