TypeScript에서 객체 리터럴의 유형 정의


345

TypeScript 클래스에서는 다음과 같이 속성 유형을 선언 할 수 있습니다.

class className {
  property: string;
};

객체 리터럴에서 속성 유형을 어떻게 선언합니까?

다음 코드를 시도했지만 컴파일되지 않습니다.

var obj = {
  property: string;
};

다음과 같은 오류가 발생합니다.

현재 범위에 'string'이름이 없습니다.

내가 잘못하고 있거나 버그입니까?

답변:


423

당신은 꽤 가깝습니다. 당신은로 대체해야 =합니다 :. 객체 유형 리터럴 (사양 섹션 3.5.3 참조) 또는 인터페이스를 사용할 수 있습니다. 객체 타입 리터럴을 사용하는 것은 당신이 가진 것에 가깝습니다.

var obj: { property: string; } = { property: "foo" };

그러나 인터페이스를 사용할 수도 있습니다

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };

14
캐스트 운영자와 @Rick Love의 DRY (Do n't Repeat Yourself) 옵션은 훨씬 깔끔해 보입니다. downvoting하지 않고 그냥 댓글을 달기 ...
spechter

나는 이것이 얼마 전에 답변되었다는 것을 알고 있지만 클래스에 속성뿐만 아니라 메소드가있을 때 문제가 발생할 수 있다고 가정하고 잘못 생각합니까? 클래스는 초기화되지 않고 속성 만 할당하므로 클래스에서 메서드를 호출하면 null 예외가 발생합니다. 기본적으로 우리가 만든 객체는 유형을 지정하기 때문에 클래스로 '동작'만하지만 실제로는 해당 클래스의 인스턴스가 아닙니다. 즉, 'new'키워드를 사용하여 클래스를 만들어야합니다. 그리고 우리는 new class () {prop : 1}; 예를 들어 C #에서와 같이 TS에서
DeuxAlpha

@DeuxAlpha 인터페이스를 할당하는데 메소드를 가질 수 없습니다. 나는 당신이 이런 수업에 배정 될 수 있다고 믿지 않습니다.
Mog0

사양에 대한 링크는 좋을 것입니다 :)
ahong

@ DeuxAlpha 이것은 클래스 객체가 아닌 객체 리터럴을 생성합니다. 또한 인터페이스는 메소드를 가질 수 있습니다. 인터페이스가 메소드를 정의하는 경우 객체 리터럴도 메소드를 정의해야합니다.이 값은 null이 아닙니다. 객체 리터럴은 인터페이스가 정의한 모든 것을 충족해야합니다. 그렇지 않으면 유형 시스템에 오류가 표시됩니다.
Rick Love

291

2019-05-15 업데이트 (대체 코드 패턴 개선)

const더 많은 기능 코드 를 사용 하고 혜택을 얻은 후에 수년이 지난 후 대부분의 경우 아래를 사용하지 않는 것이 좋습니다. (객체를 만들 때 유형 시스템을 유형을 유추하지 않고 특정 유형으로 강제하는 것은 종종 무언가 잘못되었음을 나타냅니다).

대신 const가능한 한 변수를 사용 하고 객체를 마지막 단계로 작성하는 것이 좋습니다 .

const id = GetId();
const hasStarted = true;
...
const hasFinished = false;
...
return {hasStarted, hasFinished, id};
  • 이렇게하면 명시 적으로 입력 할 필요없이 모든 것을 올바르게 입력합니다.
  • 필드 이름을 다시 입력 할 필요가 없습니다.
  • 이것은 내 경험에서 가장 깨끗한 코드로 이어집니다.
  • 이를 통해 컴파일러는 더 많은 상태 확인을 제공 할 수 있습니다 (예를 들어, 여러 위치로 반환하는 경우 컴파일러는 동일한 유형의 객체가 항상 반환되도록합니다. 이렇게하면 각 위치에서 전체 반환 값을 선언하도록 장려 함) 그 가치의 의도).

추가 2020-02-26

실제로 초기화 할 수있는 유형이 필요한 경우 : 널 입력 가능 결합 유형 (널 또는 유형)으로 표시하십시오. 타입 시스템은 먼저 값을 가지지 않고 사용하지 못하게합니다.

tsconfig.json 엄격한 null 검사를 활성화해야합니다.

"strictNullChecks": true

그런 다음이 패턴을 사용하여 유형 시스템이 우발적 인 널 / 정의되지 않은 액세스로부터 보호합니다.



const state = {
    instance: null as null | ApiService,
    // OR
    // instance: undefined as undefined | ApiService,

};

const useApi = () => {
    // If I try to use it here, the type system requires a safe way to access it

    // Simple lazy-initialization 
    const api = state?.instance ?? (state.instance = new ApiService());
    api.fun();

    // Also here are some ways to only access it if it has value:

    // The 'right' way: Typescript 3.7 required
    state.instance?.fun();

    // Or the old way: If you are stuck before Typescript 3.7
    state.instance && state.instance.fun();

    // Or the long winded way because the above just feels weird
    if (state.instance) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans way
    if (state.instance != null) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans 
    // AND I was told to always use triple === in javascript even with null checks way
    if (state.instance !== null && state.instance !== undefined) { state.instance.fun(); }
};

class ApiService {
    fun() {
        // Do something useful here
    }
}

99 %의 경우 아래를 수행하지 마십시오.

2016-02-10 업데이트-TSX 처리 (감사 @Josh)

asTSX 에는 연산자를 사용하십시오 .

var obj = {
    property: null as string
};

더 긴 예 :

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};

원래 답변

캐스트 연산자를 사용하여 간결하게 만드십시오 (널을 원하는 유형으로 캐스트하여).

var obj = {
    property: <string> null
};

더 긴 예 :

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};

두 부분으로 구성하는 것 (하나는 형식을 선언하고 다른 하나는 기본값을 선언하는 것)보다 훨씬 낫습니다.

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};

10
TSX (TSX가있는 TSX)를 사용하는 경우 꺾쇠 괄호 이름을 사용할 수 없으므로 이러한 선 property: null as string은 중요한 차이점이 as연산자 와 같은 형태가 됩니다.
Josh

2
@RickLove 이것이 실제로 객체 변수의 유형을 제한합니까, 아니면 할당 될 때 유형을 지정하는 유일한 방법입니까? 다시 말해, call두 번째 예에서 변수 에 할당 한 후 완전히 다른 유형을 할당 할 수 있습니까?
다니엘 그리 콤

3
이것은 답변이어야합니다
Drew R

4
작동하지 않는. Error:(33, 15) TS2352:Type 'null' cannot be converted to type 'string'.
slideshowp2

2
이것은 언어의 기능을 남용하는 것입니까, 아니면 실제로 합법적입니까? oficial 문서에 mor 읽기에 대한 링크를 제공 할 수 있습니까? 감사!
Qwerty

31

아무도 이것을 언급하지 않은 것에 놀랐습니다.하지만 유형의 쌍 ObjectLiteral을 허용 하는 인터페이스를 만들 수 있습니다 .key: valuestring: any

interface ObjectLiteral {
  [key: string]: any;
}

그런 다음 다음과 같이 사용하십시오.

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};

또한 보너스는 원하는 수의 객체에서이 인터페이스를 필요한만큼 여러 번 재사용 할 수 있다는 것입니다.

행운을 빕니다.


3
이것은 나쁜 생각입니다. 타입 시스템을 무가치하게 만듭니다. 타입 스크립트의 요점은 타입 시스템이 오류를 방지하고 툴링에서 더 나은 자동 완성 기능을 제공 할 수 있도록하는 것입니다. 이것은 기본적으로 타입 스크립트의 모든 이점을 비활성화합니다. 위 예제에서 인터페이스를 사용하지 않는 것이 좋습니다.
Rick Love

1
@RickLove 나는 매우 동의하지 않습니다. 이것은 여러 속성이 선택 사항 일 때 매우 유용하지만 여전히 모든 유형을 명확하게 정의하려고합니다 (예 : 함수의 인수 포함). 이것은 단순히 구문 설탕으로 볼 수 있으며 문자 그대로 인터페이스 속성스프레드 연산자 처럼 작동 합니다 .
CPHPython

@CPHPython 왜 선택적 유형을 특정 유형으로 지정하지 않습니까? 코드 타임에 이름을 알 수없는 경우 (즉, 데이터베이스 나 외부 소스에서 온 이름) 경우에만 이것이 의미가 있습니다. 또한 복잡한 인수 조합의 경우 유니온 유형이 효과적입니다. 특정 이름으로 코딩하는 경우 가능하면 이름을 정의해야합니다. 논리에 영향을 미치지 않는 데이터 일 경우 유형 시스템에서 제외하십시오.
Rick Love

1
@RickLove "코드 이름에 이름이 알려져 있지 않다"-> 이것은 실용적이고 좋은 예이며, 이러한 키 유형의 값이 알려져 있으며 모두 동일합니다 (예 : string ). 값의 유형 정의로서 어떤 부분도 [key: string]아닌 부분 의 사용만을 옹호하고 있다는 점을 염두에 두어야합니다 ... 그것은 실제로 유형의 유용성을 취합니다.
CPHPython

1
문자열과 숫자를 추가하고 다른 유형은 추가하지 않으려면 어떻게해야합니까?
DonkeyBanana 19

14

타입 주석을 작성하려는 경우 구문은 다음과 같습니다.

var x: { property: string; } = ...;

객체 리터럴을 작성하려는 경우 구문은 다음과 같습니다.

var x = { property: 'hello' };

코드가 값 위치에 유형 이름을 사용하려고합니다.


10
당신 var x: { property: string; } = ...;은 애타게입니다! 줄임표가 올바른 구문이되기를 바랍니다 var x: { property: string; } = { property: 'hello' };.
Jason Kleban

10

TypeScript에서 객체를 선언하면 다음 구문을 사용합니다.

[access modifier] variable name : { /* structure of object */ }

예를 들면 다음과 같습니다.

private Object:{ Key1: string, Key2: number }

7

당신이에 typings를 추가하려는 경우 탈구 함수에 인수 예를 들어, 객체 리터럴, 구문은 다음과 같습니다

function foo({ bar, baz }: { bar: boolean, baz: string }) {
  // ...
}

foo({ bar: true, baz: 'lorem ipsum' });

5

속성의 유형이 동일한 경우 사전 정의 된 유틸리티 유형을 사용할 수 있습니다 Record.

type Keys = "property" | "property2"

var obj: Record<Keys, string> = {
  property: "my first prop",
  property2: "my second prop",
};

더 나아가서 속성 값에 대한 사용자 정의 유형을 정의 할 수 있습니다.

type Keys = "property" | "property2"
type Value = "my prop" | "my other allowed prop"

var obj: Record<Keys, Value> = {
  property: "my prop",
  property2: "my second prop", // TS Error: Type '"my second prop"' is not assignable to type 'Value'.
};

2
정확히 내가 필요한 것. 감사! 승리를위한 타이프 스크립트!
Audacitus

나는 또한 여기 let대신 사용 합니다 var.
Fwd079

3
// Use ..

const Per = {
  name: 'HAMZA',
  age: 20,
  coords: {
    tele: '09',
    lan: '190'
  },
  setAge(age: Number): void {
    this.age = age;
  },
  getAge(): Number {
    return age;
  }
};
const { age, name }: { age: Number; name: String } = Per;
const {
  coords: { tele, lan }
}: { coords: { tele: String; lan: String } } = Per;

console.log(Per.getAge());

3
안녕하세요, SO에 오신 것을 환영합니다! 당신의 대답을 전혀 확장시킬 수 있습니까? 이것이 어떻게 / 왜 작동하는지 설명하는 것이 도움이 될 것입니다.
파티 반지

1

귀하의 코드에서 :

var obj = {
  myProp: string;
};

실제로 객체 리터럴을 작성하고 변수 문자열을 특성 myProp에 지정합니다. 매우 나쁜 연습이지만 실제로는 유효한 TS 코드입니다 (사용하지 마십시오!).

var string = 'A string';

var obj = {
  property: string
};

그러나 원하는 것은 객체 리터럴이 입력되는 것입니다. 이것은 다양한 방법으로 달성 될 수 있습니다 :

상호 작용:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };

맞춤 유형 :

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };

캐스트 연산자 :

var obj = {
    myString: <string> 'hi',
    myNumber: <number> 132,
};

객체 유형 리터럴 :

var obj: { property: string; } = { property: "Mystring" };
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.