在TypeScript中将符号用作对象键类型

时间:2019-11-30 16:51:46

标签: javascript typescript types symbols

由于MDN说,我正尝试将symbol作为键类型来定义对象。

  

符号值可以用作对象属性的标识符[...]

但是将其用作键属性的类型:

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

导致以下错误:

  

TS1023:索引签名参数类型必须为“字符串”或“数字”。

即使它也可以用作索引类型。 我正在使用最新的打字稿版本(v3.7.2),发现了相关的问题:

我也看过typescript symbol docs,但它们仅显示了如何将其用作值而不是类型。

示例:

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

2 个答案:

答案 0 :(得分:2)

不幸的是,目前在TypeScript中这是不可能的。如果您必须与某些希望使用此符号或确实希望使用符号作为键的API进行互操作,则可以使用以下笨拙的版本:

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

答案 1 :(得分:1)

机会很好,symbolsindex signatures中的其他键类型将是implementedTypeScript 4.2(请参阅Pull Request)。

您可以在staging Playground中测试该功能:

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"]

目前,SymbolIndextrigger an error

索引签名参数类型必须为“字符串”或“数字”。(1023)


话虽如此,如果您只想要一个带有符号且没有索引签名的对象类型,那么您今天就可以这样做(Playground):

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