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

Sim*_*mon 30 javascript types symbols typescript

我试图用符号定义一个对象作为键类型,因为 MDN 说:

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

但是使用它作为键属性的类型:

type obj = {
    [key: symbol | string]: string
}
Run Code Online (Sandbox Code Playgroud)

导致以下错误:

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

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

我还查看了打字稿符号文档,但它们只显示了如何将其用作值,而不是类型。

例子:

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

const sym = Symbol('My symbol');
obj[sym] = 'Hi';
Run Code Online (Sandbox Code Playgroud)

Microsoft/TypeScript 上的问题

打开功能请求

Dmi*_*riy 7

不幸的是,目前在 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
Run Code Online (Sandbox Code Playgroud)


for*_*d04 5

TypeScript 4.4允许在索引签名中使用符号

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"]
Run Code Online (Sandbox Code Playgroud)

操场

使用旧版本,SymbolIndex会触发错误

索引签名参数类型必须是“字符串”或“数字”。(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
Run Code Online (Sandbox Code Playgroud)

操场