C #에서와 같이 사전 유형으로 TypeScript 객체


336

객체를 사전으로 사용하는 JavaScript 코드가 있습니다. 예를 들어 '개인'개체는 전자 메일 주소를 사용하여 일부 개인 정보를 보관합니다.

var people = {<email> : <'some personal data'>};

adding   > "people[<email>] = <data>;" 
getting  > "var data = people[<email>];" 
deleting > "delete people[<email>];"

Typescript에서 이것을 설명 할 수 있습니까? 또는 배열을 사용해야합니까?


5
이전 게시물 그러나 ES6지도가 있습니다
올드 Badman 회색

답변:


547

최신 버전의 타이프 스크립트에서는 다음을 사용할 수 있습니다.

type Customers = Record<string, Customer>

이전 버전에서는 다음을 사용할 수 있습니다.

var map: { [email: string]: Customer; } = { };
map['foo@gmail.com'] = new Customer(); // OK
map[14] = new Customer(); // Not OK, 14 is not a string
map['bar@hotmail.com'] = 'x'; // Not OK, 'x' is not a customer

매번 전체 유형 주석을 입력하지 않으려는 경우 인터페이스를 만들 수도 있습니다.

interface StringToCustomerMap {
    [email: string]: Customer;
}

var map: StringToCustomerMap = { };
// Equivalent to first line of above

2
컴파일러가 인덱스를 문자열로 제한하도록하는 유용한 방법입니다. 흥미 롭군 인덱스 유형을 문자열이나 정수 이외의 것으로 지정할 수는 없지만 네이티브 JS 객체 인덱스에 매핑되기 때문에 의미가 있습니다.
Ken Smith

5
당신은 이것을 알고 있을지도 모르지만,이 접근법에는 몇 가지 잠재적 인 문제가 있습니다. 가장 큰 방법은 모든 멤버를 반복하는 안전하고 쉬운 방법이 없다는 것입니다. 예를 map들어이 코드 는 두 멤버 를 포함 하고 있음을 보여줍니다 . (<any> Object.prototype) .something = function () {}; 고객 클래스 {} var map : {[이메일 : 문자열] : 고객; } = {}; map ['foo@gmail.com '] = 신규 고객 (); for (var i in map) {console.log (map [i])}
Ken Smith

5
어떻게 제거합니까?
TDaver

24
또 다른 흥미로운 접근법은 다음과 같습니다. interface MapStringTo <T> {[key : string] : T; } 다음과 같이 변수를 선언합니다.var map:MapStringTo<Customer> = {};
orellabac

1
인덱스 제약 조건이 더 이상 작동하지 않습니다. 더 읽어보세요.
David Sherret

127

지도 와 같은 객체 를 사용하는 것 외에도 , 얼마 동안 실제 Map객체 가 있었는데, ES6로 컴파일 할 때 또는 ES6 유형 정의 로 폴리 필을 사용할 때 TypeScript에서 사용할 수 있습니다 .

let people = new Map<string, Person>();

Object약간 다른 구문으로와 같은 기능을 지원 합니다.

// Adding an item (a key-value pair):
people.set("John", { firstName: "John", lastName: "Doe" });

// Checking for the presence of a key:
people.has("John"); // true

// Retrieving a value by a key:
people.get("John").lastName; // "Doe"

// Deleting an item by a key:
people.delete("John");

이것만으로 다음 과 같은과 같은 객체 를 사용하는 것보다 몇 가지 장점이 있습니다.

  • 문자열 기반이 아닌 키 (예 : 숫자 또는 객체)를 지원 하지 않음 Object(아니오, Object숫자를 지원하지 않는 경우 문자열로 변환)
  • 사용하지 않는 오류를 덜 룸 --noImplicitAnyA가로, Map항상이 키의 유형과 유형을 객체가있는 반면, 인덱스-서명이 없습니다
  • 항목 (키-값 쌍)을 추가 / 제거하는 기능은 속성을 생성하는 것과 달리 작업에 최적화 되어 있습니다.Object

또한 Map객체는 일반적인 작업에보다 강력하고 우아한 API를 제공하며, 대부분 Object도우미 함수를 해킹하지 않고 간단한 기능으로 는 사용할 수 없습니다 (일부는 ES5 대상 이하의 경우 완전한 ES6 반복자 / 반복 가능한 폴리 필이 필요하지만).

// Iterate over Map entries:
people.forEach((person, key) => ...);

// Clear the Map:
people.clear();

// Get Map size:
people.size;

// Extract keys into array (in insertion order):
let keys = Array.from(people.keys());

// Extract values into array (in insertion order):
let values = Array.from(people.values());

2
대단해! 그러나 JSON.stringify()슬프게도을 사용 하여 잘못 직렬화 되었으므로 socket.io 등을 사용할 수 있습니다.
Lion

@Lion-네, Map직렬화는 다소 재미 있습니다. 우선 직렬화하기 전에 키-값 쌍 객체로 변환 한 다음 다시 (예 : 객체 { key: "John", value: { firstName: "John" } }) 변환합니다.
John Weisz

2
나는 평범한 오래된 물체 대신 맵을 사용하는 실수를 저지르고 직렬화가 실제로 나를 얻었습니다. 내 의견으로는 명확하게 조종하십시오.
user378380

1
이것은 아름답다. 마침내지도에 빠져들게해서 기뻐요. 키를 강력하게 입력하는 것이 훨씬 쉽기 때문에 일반적인 키 맵 / 사전 구조를 대체합니다.
Methodician

77

다음과 같은 템플릿 인터페이스를 사용할 수 있습니다.

interface Map<T> {
    [K: string]: T;
}

let dict: Map<number> = {};
dict["one"] = 1;

7
이는 es6 Map 유형과 충돌합니다. 인덱스 제약 조건이 무시되므로 다른 답변보다 낫습니다.
Old Badman Grey

사전에 키가 있는지 어떻게 확인합니까?
samneric

dict.hasOwnProperty ( 'key')
Dimitar Mazhlekov

1
혼란을 피하기 위해 Map 대신 Dictionary를 사용하고 리터럴 객체 표기법을 사용할 수 있습니다.let dict: Dictionary<number> = { "one": 1, "two": 2 };
PhiLho

8

typescript에서 레코드 유형을 사용할 수도 있습니다.

export interface nameInterface { 
    propName : Record<string, otherComplexInterface> 
}

5

Lodash는 간단한 사전 구현을 가지고 있으며 TypeScript를 잘 지원합니다.

Lodash를 설치하십시오.

npm install lodash @types/lodash --save

가져 오기 및 사용법 :

import { Dictionary } from "lodash";
let properties : Dictionary<string> = {
    "key": "value"        
}
console.log(properties["key"])

3

Record이것을 위해 사용할 수 있습니다 :

https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt

예 (AppointmentStatus 열거 형과 일부 메타 데이터 간의 매핑) :

  const iconMapping: Record<AppointmentStatus, Icon> = {
    [AppointmentStatus.Failed]: { Name: 'calendar times', Color: 'red' },
    [AppointmentStatus.Canceled]: { Name: 'calendar times outline', Color: 'red' },
    [AppointmentStatus.Confirmed]: { Name: 'calendar check outline', Color: 'green' },
    [AppointmentStatus.Requested]: { Name: 'calendar alternate outline', Color: 'orange' },
    [AppointmentStatus.None]: { Name: 'calendar outline', Color: 'blue' }
  }

이제 인터페이스를 가치로 사용하십시오.

interface Icon { Name: string Color: string }

용법:

const icon: SemanticIcon = iconMapping[appointment.Status]


이것은 매우 유용합니다. 문자열 enum이나 class/objectfor 를 사용 하시겠습니까 AppointmentStatus?
Drenai

@Drenai는 중요하지 않습니다. 선호하는 것입니다.
Nick N.

-2

타이프 스크립트에 강력한 형식의 쿼리 가능한 컬렉션 을 제공하는 라이브러리가 있습니다 .

컬렉션은 다음과 같습니다

  • 명부
  • 사전

라이브러리를 ts-generic-collections 라고 합니다. ( GitHub의 소스 코드 )

사전을 만들고 아래와 같이 쿼리 할 수 ​​있습니다.

  it('firstOrDefault', () => {
    let dictionary = new Dictionary<Car, IList<Feature>>();

    let car = new Car(1, "Mercedez", "S 400", Country.Germany);
    let car2 = new Car(2, "Mercedez", "S 500", Country.Germany);

    let features = new List<Feature>();

    let feature = new Feature(1, "2 - Door Sedan");
    features.add(feature);

    dictionary.add(car, features);

    features = new List<Feature>();
    feature = new Feature(2, "4 - Door Sedan");
    features.add(feature);

    dictionary.add(car2, features);

    //query
    let first = dictionary.firstOrDefault(x => x.key.name == "Mercedez");

    expect(first.key.id = 1);
  });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.