39

I'm trying to define an object with a symbol as key-type since MDN says:

A symbol value may be used as an identifier for object properties [...]

But using it as type for the key-property:

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

results in the following error:

TS1023: An index signature parameter type must be either 'string' or 'number'.

even it can be used as index-type. I'm using the latest typescript version (v3.7.2), related questions I've found:

I've also took a look at the typescript symbol docs but they only show how it's used as value, not as type.

Example:

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

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

Issue on Microsoft/TypeScript

Open feature request

5
  • 1
    I think TypeScript only supports specific symbols in its object type declarations. Do you really want any symbol? Maybe show an example of how you want to use your type obj - I doubt that all symbol-keyed properties will be strings. Commented Nov 30, 2019 at 16:59
  • @Bergi I've added an example, maybe I've overseen something but I can't find a way to bring ts to accept a symbol (without using any which is bad practice). Commented Nov 30, 2019 at 17:06
  • See github.com/Microsoft/TypeScript/issues/24587 Commented Nov 30, 2019 at 17:22
  • 1
    am not sure if am right but did you try using Map<Symbol,String> as we have Map , if that would serve the purpose of what you are trying to achieve Commented Nov 30, 2019 at 18:09
  • 2
    Same issue for me, I guess the annoying part is the false advertising of how "TS is a superset of JS" - well, not exactly. this is a perfect example of that. Commented Mar 1, 2020 at 21:48

2 Answers 2

13

TypeScript 4.4 allows symbols in index signatures:

type SymbolIndex = {
    [key: symbol | string]: string // works
}

const sym = Symbol("descr");
const t1: SymbolIndex = {
    "foo": "bar",
    [Symbol.iterator]: "qux",
    sym: "sym"
};

// all result in string
t1.foo 
t1.sym 
t1[Symbol.iterator]
t1["oh"]

Playground

With older versions, SymbolIndex will trigger an error:

An index signature parameter type must be either 'string' or 'number'.(1023)

Alternative

If you just want an object type with symbols and no index signature, you can already do that today:

const sym = Symbol() // note const (no let) 
type O = {
    foo: string
    [Symbol.iterator]: string
    [sym]: number
}

let o: O = { [sym] : 3, [Symbol.iterator]: "bar", foo: "qux"}

let { [sym]: symVal } = o

Playground

Sign up to request clarification or add additional context in comments.

5 Comments

If we have two Symbol() then how can we use [Symbol.iterator] for two different Symbol
@SubratoPatnaik I honestly don't understand your question. Symbol.iterator is a well-known symbol and can be added once per object as property key to provide a default iterator, usable with for...of. It is also not clear, if you mean type or value space.
I can see the code in the playground and it runs without any problem. However, after I copied them to my vscode with TypeScript 4.3, it still tells me An index signature parameter type must be either 'string' or 'number'.ts(1023)
@Huan that feature has been delayed to upcoming TS 4.4, updated answer
Thanks, @ford04! I have updated to TypeScript 4.4-dev and everything works now.
8

Unfortunately this is not possible at the moment in TypeScript. If you have to interoperate with some APIs that expect this or really want to use symbols as keys, you can do this awkward version:

// 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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.