typescript - Anahtarların birden fazla tipe sahip olduğu bir durumda, bir typed Map'in başlangıç değerlerini yapıcıda nasıl ayarlayabilirim


Bir Map oluşturmak istiyorum, burada anahtar bir number veya bir string olabilir. Bunu yapıcıda değerlerle başlatmak istiyorum. Bazı girişlerin number anahtarı var ve bazılarının string anahtarı var.

Ama bir TypeScript hatası alıyorum. Bu bir TypeScript hatası mı, yoksa ben yanlış mı yapıyorum?

type MyMap = Map<string | number, string>;

// Errors, incorrectly?
const myMapWithMixedKeys: MyMap = new Map([
  ['abc', 'String key'],
  [123, 'Number key']
]);

// All fine
myMapWithMixedKeys.set('abcd', 'String key');
myMapWithMixedKeys.set(1234, 'Number key');

const myMapStrings: MyMap = new Map([
  ['abc', 'String key'],
  ['abcd', 'String key']
]);

const myMapNumbers: MyMap = new Map([
  [123, 'Number key'],
  [1234, 'Number key']
]);

Hata:

No overload matches this call.
  Overload 1 of 3, '(iterable: Iterable<readonly [string, string]>): Map<string, string>', gave the following error.
    Argument of type '([string, string] | [number, string])[]' is not assignable to parameter of type 'Iterable<readonly [string, string]>'.
      Types of property '[Symbol.iterator]' are incompatible.
        Type '() => IterableIterator<[string, string] | [number, string]>' is not assignable to type '() => Iterator<readonly [string, string], any, undefined>'.
          Type 'IterableIterator<[string, string] | [number, string]>' is not assignable to type 'Iterator<readonly [string, string], any, undefined>'.
            Types of property 'next' are incompatible.
              Type '(...args: [] | [undefined]) => IteratorResult<[string, string] | [number, string], any>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult<readonly [string, string], any>'.
                Type 'IteratorResult<[string, string] | [number, string], any>' is not assignable to type 'IteratorResult<readonly [string, string], any>'.
                  Type 'IteratorYieldResult<[string, string] | [number, string]>' is not assignable to type 'IteratorResult<readonly [string, string], any>'.
                    Type 'IteratorYieldResult<[string, string] | [number, string]>' is not assignable to type 'IteratorYieldResult<readonly [string, string]>'.
                      Type '[string, string] | [number, string]' is not assignable to type 'readonly [string, string]'.
                        Type '[number, string]' is not assignable to type 'readonly [string, string]'.
                          Types of property '0' are incompatible.
                            Type 'number' is not assignable to type 'string'.
  Overload 2 of 3, '(entries?: readonly (readonly [string, string])[] | null | undefined): Map<string, string>', gave the following error.
    Argument of type '([string, string] | [number, string])[]' is not assignable to parameter of type 'readonly (readonly [string, string])[]'.
      Type '[string, string] | [number, string]' is not assignable to type 'readonly [string, string]'.
        Type '[number, string]' is not assignable to type 'readonly [string, string]'.ts(2769)

Cevap #1

Sorun, TS'nin bir new Map() türünü ilk değere göre çıkarmasıdır. Sadece let m=new Map([[1, 1], ['2', 2]]) yazsanız bile, herhangi bir tür belirtmeden bu olur.

(Bu arada: Bir şey yazdığınızda dizilerde de olur, örneğin let a=new Array(1, '2')).

Bunu çözmek için TS'yi Map'in türünün birleşim türü olduğunu anlamaya zorlamalısınız. Bunu yapmanın iki yolunu biliyorum:

const myMapWithMixedKeys: MyMap = new Map<string | number, string>([
  ['abc', 'String key'],
  [123, 'Number key']
]);

Veya :

const myMapWithMixedKeys: MyMap = new Map([
  ['abc' as string | number, 'String key'],
  [123, 'Number key']
]);

Oyun Alanını Gör

DÜZENLEME: Bence daha iyi bir çözüm buldum.

Bunun yerine:

type MyMap = Map<string | number, string>;

Yaz :

class MyMap extends Map<string | number, string> { }

Ve şimdi her şey iyi çalışıyor. Güncellenmiş Playground'a bakın

İlgili makaleler