programing

TypeScript에서 일반 JavaScript 개체 유형을 대상으로 하는 방법이 있습니까?

batch 2023. 6. 25. 18:35
반응형

TypeScript에서 일반 JavaScript 개체 유형을 대상으로 하는 방법이 있습니까?

2021년 업데이트

새로운 기능을 사용하는 작업 솔루션은 다음 답변을 참조하십시오. https://stackoverflow.com/a/59647842/1323504


저는 어떤 종류의 평범한 자바스크립트 객체를 반환하는 함수를 쓰려고 합니다.그 물체의 특징은 알려지지 않았고, 현재로서는 흥미롭지 않으며, 단지 그것이 평범한 물체라는 사실뿐입니다.예를 들어 jQuery의 값을 만족시키는 일반 객체를 의미합니다.isPlainObject기능.예를들면

{ a: 1, b: "b" }

일반적인 목적이지만,

var obj = new MyClass();

그것은 "유효한" 객체가 아닙니다.constructor아닙니다ObjectjQuery는 보다 정확한 작업을 수행합니다.$.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", ...);
  }
  ...
}

이제 제가 소비자 계층에서 그것을 부를 때, 저는 이런 것을 할 수 있습니다.

export class MyViewModelClass {
  ...
  LoadResult(id: number): JQueryPromise<MyControllerResult> { // note the MyControllerResult strong typing here
    return MyController.GetResult(id).then(plainResult => new MyControllerResult(plainResult));
  }
  ...
}

그리고 이제 컨트롤러 방식이 되돌아온다고 상상해 보십시오.JQueryPromise<any>또는JQueryPromise<Object>그리고 이제 내가 우연히 글을 쓴다고 상상해 보세요.done대신에then숨겨진 오류가 있습니다. 뷰 모델 메소드가 올바른 약속을 반환하지 않지만 컴파일 오류는 발생하지 않기 때문입니다.

내게 이런 상상이 있다면,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 에서 적용한 것입니다.

프리미티브는 mdn문서 > 프리미티브를 참조하십시오.


대안적인 해결책은 sindresorhus / type-fest 라이브러리를 사용하거나 https://github.com/sindresorhus/type-fest/blob/main/source/basic.d.ts 에서 제공하는 구현을 사용하는 것입니다.

제 코드에는 당신이 요구하는 것과 유사한 것이 있습니다.

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

재귀적 유형(원시 솔루션)을 시도할 수 있습니다.

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 플레이그라운드 링크

허용된 답변과의 차이점은 기본값뿐만 아니라 일반 개체에도 복잡한 값이 포함될 수 있다는 것입니다.

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 플레이그라운드 링크

언급URL : https://stackoverflow.com/questions/42027864/is-there-any-way-to-target-the-plain-javascript-object-type-in-typescript

반응형