Używanie symbolu jako typu klucza obiektowego w TypeScript

20

Próbuję zdefiniować obiekt z symbolem jako klucz, ponieważ MDN mówi:

Wartość symbolu można wykorzystać jako identyfikator właściwości obiektu [...]

Ale używając go jako typu dla właściwości klucz:

type obj = {
    [key: symbol | string]: string
}

powoduje następujący błąd:

TS1023: Typ parametru podpisu indeksu musi być „ciągiem” lub „liczbą”.

nawet może być użyty jako indeks. Korzystam z najnowszej wersji maszynopisu ( v3.7.2), powiązane pytania, które znalazłem:

Przyjrzałem się również dokumentom symboli maszynopisu, ale pokazują one tylko, w jaki sposób są używane jako wartość, a nie jako typ.

Przykład:

const obj = {} as {
    [key: number | symbol]: string // Won't work
};

const sym = Symbol('My symbol');
obj[sym] = 'Hi';

Problem dotyczący Microsoft / TypeScript

Otwórz żądanie funkcji

Szymon
źródło
Myślę, że TypeScript obsługuje tylko określone symbole w deklaracjach typów obiektów. Naprawdę chcesz jakieś symbol ? Może pokaż przykład, w jaki sposób chcesz używać swojego type obj- wątpię, aby wszystkie właściwości z kluczem symbolicznym były strings.
Bergi,
@Bergi Dodałem przykład, być może coś nadzorowałem, ale nie mogę znaleźć sposobu, aby zachęcić ts do przyjęcia symbolu (bez użycia, anyco jest złą praktyką).
Simon
nie jestem pewien, czy Map<Symbol,String>mam rację, ale czy spróbowałeś użyć mapy, którą mamy, czy to by służyło celowi, który starasz się osiągnąć
pavan kumar
Dla mnie ten sam problem, chyba denerwująca jest fałszywa reklama tego, jak „TS jest nadzbiorem JS” - cóż, niezupełnie. to jest tego doskonały przykład.
Patrick

Odpowiedzi:

3

Niestety obecnie nie jest to możliwe w TypeScript. Jeśli musisz współpracować z niektórymi interfejsami API, które tego oczekują lub naprawdę chcesz używać symboli jako kluczy, możesz wykonać tę niezręczną wersję:

// Ensure we can not pass regular map to our custom functions
type SymbolMapTag = { readonly symbol: unique symbol }

type SymbolMap = SymbolMapTag & {
    [Key in string | number | symbol]: string;
}

function set_symbol<T extends SymbolMap, TSym extends symbol>
(target: T, sym: TSym, value: T[TSym]) {
    target[sym] = value;
}

function get_symbol<T extends SymbolMap, TSym extends symbol>
(target: T, sym: TSym): T[TSym] {
    return target[sym];
}

const symbol_map = {} as SymbolMap;

const sym = Symbol('My symbol');
set_symbol(symbol_map, sym, "hi");
get_symbol(symbol_map, sym); // string


type NonSymbolMap = {
    [Key in string | number]: string;
}

const non_symbol_map = {} as NonSymbolMap;
set_symbol(non_symbol_map, sym, "hi"); // error
get_symbol(non_symbol_map, sym); // error
Dmitriy
źródło