Typescript에서 사전 선언 및 초기화


248

다음 코드가 주어지면

interface IPerson {
   firstName: string;
   lastName: string;
}

var persons: { [id: string]: IPerson; } = {
   "p1": { firstName: "F1", lastName: "L1" },
   "p2": { firstName: "F2" }
};

초기화가 거부되지 않는 이유는 무엇입니까? 결국 두 번째 개체에는 "lastName"속성이 없습니다.


11
참고 :이 이후 수정되었습니다 (정확한 TS 버전을 확실하지 않음). VS에서 이러한 오류가 발생합니다. Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.
Simon_Weaver

답변:


289

편집 : 이것은 최신 TS 버전에서 수정되었습니다. OP의 게시물에 대한 @Simon_Weaver의 의견 인용 :

참고 :이 이후 수정되었습니다 (정확한 TS 버전을 확실하지 않음). VS에서 이러한 오류가 발생합니다.Index signatures are incompatible. Type '{ firstName: string; }' is not assignable to type 'IPerson'. Property 'lastName' is missing in type '{ firstName: string; }'.


선언시 초기 데이터를 전달할 때 분명히 작동하지 않습니다. 이것이 TypeScript의 버그라고 생각하므로 프로젝트 사이트에서 버그를 제기해야합니다.

다음과 같이 선언과 초기화에서 예제를 분할하여 유형이 지정된 사전을 사용할 수 있습니다.

var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };
persons["p2"] = { firstName: "F2" }; // will result in an error

3
id상징 이 필요 합니까? 불필요한 것 같습니다.
kiewic

4
id기호를 사용하여 사전의 키 유형을 선언 할 수 있습니다. 위의 선언으로 다음을 수행 할 수 없습니다.persons[1] = { firstName: 'F1', lastName: 'L1' }
thomaux

2
어떤 이유로 든 항상이 구문을 잊어 버리십시오!
eddiew 's

12
id기호가 같은 것을 당신을 이름을 지정할 수 있습니다보다 쉽게 코드를 읽을 수 있도록하기 위해 그런 식으로 설계되었습니다. 예 { [username: string] : IPerson; }
Guy Park

1
@Robouste Lodash의 findKey 메소드를 사용하거나 기본 솔루션을 선호하는 경우 Object.entries 빌드 할 수 있습니다. 전체 키 목록을 얻으려면 Object.keys
thomaux를

82

typescript에서 사전 객체를 사용하려면 다음과 같이 인터페이스를 사용할 수 있습니다.

interface Dictionary<T> {
    [Key: string]: T;
}

클래스 속성 유형에 사용하십시오.

export class SearchParameters {
    SearchFor: Dictionary<string> = {};
}

이 클래스를 사용하고 초기화하기 위해

getUsers(): Observable<any> {
        var searchParams = new SearchParameters();
        searchParams.SearchFor['userId'] = '1';
        searchParams.SearchFor['userName'] = 'xyz';

        return this.http.post(searchParams, 'users/search')
            .map(res => {
                return res;
            })
            .catch(this.handleError.bind(this));
    }

61

초기화 유형 확인 오류가 TypeScript 버그라는 thomaux에 동의합니다. 그러나 올바른 유형 검사를 사용하여 단일 문에서 사전을 선언하고 초기화하는 방법을 찾고 싶었습니다. 이 구현은 더 길지만 containsKey(key: string)remove(key: string)메소드 와 같은 추가 기능을 추가합니다 . 0.9 릴리스에서 제네릭을 사용할 수있게되면이를 단순화 할 수있을 것으로 생각됩니다.

먼저 기본 Dictionary 클래스와 인터페이스를 선언합니다. 클래스는이를 구현할 수 없으므로 인덱서에 인터페이스가 필요합니다.

interface IDictionary {
    add(key: string, value: any): void;
    remove(key: string): void;
    containsKey(key: string): bool;
    keys(): string[];
    values(): any[];
}

class Dictionary {

    _keys: string[] = new string[];
    _values: any[] = new any[];

    constructor(init: { key: string; value: any; }[]) {

        for (var x = 0; x < init.length; x++) {
            this[init[x].key] = init[x].value;
            this._keys.push(init[x].key);
            this._values.push(init[x].value);
        }
    }

    add(key: string, value: any) {
        this[key] = value;
        this._keys.push(key);
        this._values.push(value);
    }

    remove(key: string) {
        var index = this._keys.indexOf(key, 0);
        this._keys.splice(index, 1);
        this._values.splice(index, 1);

        delete this[key];
    }

    keys(): string[] {
        return this._keys;
    }

    values(): any[] {
        return this._values;
    }

    containsKey(key: string) {
        if (typeof this[key] === "undefined") {
            return false;
        }

        return true;
    }

    toLookup(): IDictionary {
        return this;
    }
}

이제 개인별 유형과 사전 / 사전 인터페이스를 선언합니다. PersonDictionary 에서 올바른 유형을 재정의 values()하고 toLookup()반환하는 방법에 유의 하십시오.

interface IPerson {
    firstName: string;
    lastName: string;
}

interface IPersonDictionary extends IDictionary {
    [index: string]: IPerson;
    values(): IPerson[];
}

class PersonDictionary extends Dictionary {
    constructor(init: { key: string; value: IPerson; }[]) {
        super(init);
    }

    values(): IPerson[]{
        return this._values;
    }

    toLookup(): IPersonDictionary {
        return this;
    }
}

다음은 간단한 초기화 및 사용 예입니다.

var persons = new PersonDictionary([
    { key: "p1", value: { firstName: "F1", lastName: "L2" } },
    { key: "p2", value: { firstName: "F2", lastName: "L2" } },
    { key: "p3", value: { firstName: "F3", lastName: "L3" } }
]).toLookup();


alert(persons["p1"].firstName + " " + persons["p1"].lastName);
// alert: F1 L2

persons.remove("p2");

if (!persons.containsKey("p2")) {
    alert("Key no longer exists");
    // alert: Key no longer exists
}

alert(persons.keys().join(", "));
// alert: p1, p3

매우 유용한 샘플 코드. "인터페이스 IDictionary"에는 IPerson에 대한 참조가 있으므로 작은 오타가 포함되어 있습니다.
mgs

요소 수도 구현하는 것이 좋을 것입니다
nurettin

@dmck 선언 containsKey(key: string): bool;TypeScript 1.5.0-beta에서 작동하지 않습니다 . 로 변경해야합니다 containsKey(key: string): boolean;.
Amarjeet Singh

1
왜 제네릭 형식을 삭제하지 않습니까? Dictionary <T>이면 PersonDictionary 클래스를 만들 필요가 없습니다. 다음과 같이 선언하십시오. var persons = new Dictionary <IPerson> ();
Benoit

1
나는 그런 일반적인 사전을 효과적으로 사용했습니다. 여기에서 찾았습니다 : fabiolandoni.ch/…
CAK2

5

@dmck에서 영감을 얻은보다 일반적인 사전 구현은 다음과 같습니다.

    interface IDictionary<T> {
      add(key: string, value: T): void;
      remove(key: string): void;
      containsKey(key: string): boolean;
      keys(): string[];
      values(): T[];
    }

    class Dictionary<T> implements IDictionary<T> {

      _keys: string[] = [];
      _values: T[] = [];

      constructor(init?: { key: string; value: T; }[]) {
        if (init) {
          for (var x = 0; x < init.length; x++) {
            this[init[x].key] = init[x].value;
            this._keys.push(init[x].key);
            this._values.push(init[x].value);
          }
        }
      }

      add(key: string, value: T) {
        this[key] = value;
        this._keys.push(key);
        this._values.push(value);
      }

      remove(key: string) {
        var index = this._keys.indexOf(key, 0);
        this._keys.splice(index, 1);
        this._values.splice(index, 1);

        delete this[key];
      }

      keys(): string[] {
        return this._keys;
      }

      values(): T[] {
        return this._values;
      }

      containsKey(key: string) {
        if (typeof this[key] === "undefined") {
          return false;
        }

        return true;
      }

      toLookup(): IDictionary<T> {
        return this;
      }
    }

3

특성을 무시하려면 물음표를 추가하여 선택 사항으로 표시하십시오.

interface IPerson {
    firstName: string;
    lastName?: string;
}

1
질문의 요점은 왜 주어진 코드가 성을 제공하지 않고 컴파일 된 이유입니다.
Pierre Arlaud

-1

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

이 컬렉션은 다음과 같습니다.

  • 명부
  • 사전

라이브러리는 ts-generic-collections-linq라고 합니다.

GitHub의 소스 코드 :

https://github.com/VeritasSoftware/ts-generic-collections

NPM :

https://www.npmjs.com/package/ts-generic-collections-linq

이 라이브러리를 사용하면 아래와 같은 컬렉션을 만들고 List<T>쿼리 할 수 ​​있습니다.

    let owners = new List<Owner>();

    let owner = new Owner();
    owner.id = 1;
    owner.name = "John Doe";
    owners.add(owner);

    owner = new Owner();
    owner.id = 2;
    owner.name = "Jane Doe";
    owners.add(owner);    

    let pets = new List<Pet>();

    let pet = new Pet();
    pet.ownerId = 2;
    pet.name = "Sam";
    pet.sex = Sex.M;

    pets.add(pet);

    pet = new Pet();
    pet.ownerId = 1;
    pet.name = "Jenny";
    pet.sex = Sex.F;

    pets.add(pet);

    //query to get owners by the sex/gender of their pets
    let ownersByPetSex = owners.join(pets, owner => owner.id, pet => pet.ownerId, (x, y) => new OwnerPet(x,y))
                               .groupBy(x => [x.pet.sex])
                               .select(x =>  new OwnersByPetSex(x.groups[0], x.list.select(x => x.owner)));

    expect(ownersByPetSex.toArray().length === 2).toBeTruthy();

    expect(ownersByPetSex.toArray()[0].sex == Sex.F).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.length === 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[0].owners.toArray()[0].name == "John Doe").toBeTruthy();

    expect(ownersByPetSex.toArray()[1].sex == Sex.M).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.length == 1).toBeTruthy();
    expect(ownersByPetSex.toArray()[1].owners.toArray()[0].name == "Jane Doe").toBeTruthy();

이를위한 npm 패키지를 찾을 수 없음
Harry

1
@Harry-npm 패키지는 "ts-generic-collections-linq"라고합니다
Ade
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.