在 TypeScript 中使用符号作为对象键类型
Posted
技术标签:
【中文标题】在 TypeScript 中使用符号作为对象键类型【英文标题】:Using symbol as object-key type in TypeScript 【发布时间】:2020-03-25 20:19:50 【问题描述】:我正在尝试使用 symbol 定义一个对象作为键类型,因为 MDN 说:
符号值可以用作对象属性的标识符 [...]
但使用它作为键属性的类型:
type obj =
[key: symbol | string]: string
导致以下错误:
TS1023:索引签名参数类型必须是“字符串”或“数字”。
即使它可以用作索引类型。
我正在使用最新的打字稿版本(v3.7.2
),我发现的相关问题:
symbol
)
TypeScript: An index signature parameter must be a 'string' or 'number' when trying to use string | number
ES6: destructuring an object with symbols as keys(这不可能是一个解决方案 - 使用实际实例作为类型似乎有点错误,因为每个 Symbol 实例都是唯一的......)
我还查看了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
【问题讨论】:
我认为 TypeScript 只支持其对象类型声明中的特定符号。你真的想要anysymbol
吗?也许展示一个你想如何使用type obj
的例子 - 我怀疑所有符号键属性都是string
s。
@Bergi 我添加了一个示例,也许我已经监督了一些事情,但我找不到让 ts 接受符号的方法(不使用 any
这是不好的做法)。
见github.com/Microsoft/TypeScript/issues/24587
不确定是否正确,但您是否尝试使用 Map<Symbol,String>
,因为我们有 Map ,如果这可以达到您想要达到的目的
对我来说同样的问题,我想烦人的部分是“TS 是 JS 的超集”的虚假广告——嗯,不完全是。这是一个完美的例子。
【参考方案1】:
不幸的是,目前这在 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
【讨论】:
【参考方案2】:TypeScript 4.4 允许symbols 进入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
对于旧版本,SymbolIndex
将触发 error:
索引签名参数类型必须是“字符串”或“数字”。(1023)
另类
如果您只想要一个带有符号且没有索引签名的对象类型,那么您今天已经可以做到了:
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
【讨论】:
如果我们有两个Symbol()
,那么我们如何将[Symbol.iterator]
用于两个不同的符号
@SubratoPatnaik 老实说,我不明白你的问题。 Symbol.iterator
是一个众所周知的符号,可以为每个对象添加一次作为属性键以提供a default iterator,可与for...of
一起使用。如果您指的是类型空间还是值空间,也不清楚。
我可以在操场上看到代码,它运行没有任何问题。但是,在我使用 TypeScript 4.3 将它们复制到我的 vscode 之后,它仍然告诉我 An index signature parameter type must be either 'string' or 'number'.ts(1023)
@Huan 该功能已延迟到即将推出的 TS 4.4,更新答案
谢谢,@ford04!我已经更新到 TypeScript 4.4-dev,现在一切正常。以上是关于在 TypeScript 中使用符号作为对象键类型的主要内容,如果未能解决你的问题,请参考以下文章