简体   繁体   English

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

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

UPDATE 2021 2021 年更新

For a working solution using newer features see this answer https://stackoverflow.com/a/59647842/1323504对于使用较新功能的有效解决方案,请参阅此答案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我正在尝试编写一个 function,我想指出它返回某种普通的JavaScript object。该对象的签名未知,目前并不有趣,只是它是一个普通的 object。我的意思是一个普通的object 满足例如 jQuery 的isPlainObject function。例如

{ a: 1, b: "b" }

is a plain object, but是一个普通的 object,但是

var obj = new MyClass();

is not a "plain" object, as its constructor is not Object .不是“普通”object,因为它的constructor不是Object jQuery does some more precise job in $.isPlainObject , but that's out of the question's scope. jQuery 在$.isPlainObject中做了一些更精确的工作,但这与 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 .如果我尝试使用Object类型,那么它也将与任何自定义对象兼容,因为它们是从Object继承的。

Is there a way to target the "plain object" type in TypeScript?有没有办法在 TypeScript 中定位“普通对象”类型?

I would like a type , which would satisfy this for example.我想要一个type ,它可以满足这个要求。

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.这些存根由我的一个代码生成器生成,基于 ASP.NET MVC 控制器。

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.现在当我在消费者 class 中调用它时,我可以做这样的事情。

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> .现在假设 controller 方法返回JQueryPromise<any>JQueryPromise<Object> And now also imagine that by accident I write done instead of then .现在还想象一下,我不小心写done而不是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.现在我有一个隐藏错误,因为 viewmodel 方法不会返回正确的 promise,但我不会得到编译错误。

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.如果我有这个虚构PlainObject类型,我希望得到一个编译错误,指出PlainObject无法转换为MyControllerResult或类似的东西。

Tested in TypeScript 3.7.2:在 TypeScript 3.7.2 中测试:

For a flat plain object, you can do:对于平面对象,您可以执行以下操作:

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

For a nested plain object:对于嵌套的普通对象:

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

Code is an adaptation from https://github.com/microsoft/TypeScript/issues/3496#issuecomment-128553540代码改编自https://github.com/microsoft/TypeScript/issues/3496#issuecomment-128553540

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:问题是在 'lib.d.ts' 对象是这样定义的:

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

You can try recursive type (naive solution)您可以尝试递归类型(幼稚的解决方案)

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

Not good, not terrible :)不好,不可怕:)

I've found this to work in TS 4.9:我发现这适用于 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 Playground link TS 游乐场链接

The difference with the accepted answer is that it also allows the plain object to contain complex values, and not only primitives:与接受的答案的不同之处在于,它还允许普通 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 Playground link TS 游乐场链接

暂无
暂无

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

相关问题 有没有办法将 Ember 对象转换为普通的 javascript 对象? - Is there any way to convert Ember Object into plain javascript object? 如何在 TypeScript 中键入普通 object - How to type plain object in TypeScript 如何使用普通的旧版JavaScript JavaScript以不中断访问对象的方式导出TypeScript类 - How to export a TypeScript class in a way that won't disrupt accessing the object using plain old vanilla JavaScript 有没有办法只在打字稿中将泛型类型限制为普通对象? - Is there a way to constraint a generic type to plain objects only in typescript? Object 在 javascript/typescript 中返回类型 - Object return type in javascript/typescript 使 Typescript 从普通的 javascript 对象推断类型 - Make Typescript infer types from a plain javascript object 如何使用类转换器将 typescript class 转换为普通 javascript object - How to convert typescript class to plain javascript object with class-transformer 有什么方法可以将普通的 object 转换为 class object? - Is there any way in which we can convert plain object to class object? 有没有办法检查普通的香草 javascript object 而不是任何其他特殊类型的 object(即日期)? - Is there a way to check for just a plain vanilla javascript object as opposed to any other special kind of object (i.e. Date)? 有没有更好的方法来打字稿中的 IntrinsicAttributes &amp; TYPE - Is there any better way to IntrinsicAttributes & TYPE in Typescript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM