【发布时间】:2019-07-19 03:32:56
【问题描述】:
按照mapped types 上的文档,应该可以在 TypeScript 中使用这样的包装器:
export type Wrapped<T> = {
[P in keyof T]: T[P];
} & { _state: number }
function wrap<T extends object>(x: T): Wrapped<T> {
let xWrapped = x as Wrapped<T>
xWrapped._state = 0;
return xWrapped;
}
总的来说,这似乎运作良好,Wrapped<T> 的行为与T 完全相同。
但是,我注意到可能存在类型系统不满意的情况。例如:
let a = new Date()
let b = wrap(a)
function f(d: Date) {}
f(a) // works
f(b) // error: Property '[Symbol.toPrimitive]' is missing in type 'Wrapped<Date>' but required in type 'Date'
如何编写Wrapped<T> 的类型定义来支持Date 这样的类型?
背景: 这个简化示例背后的实际问题出现在Solid (framework),它使用a recursive version of such a wrapper 进行核心状态处理。在这种情况下,问题非常严重,因为 TypeScript 不接受 Wrapped<MyState> 为 MyState,只要在嵌套状态的某个地方存在像 Date 这样的“不可包装”类型,导致 @ 987654337@ 无处不在。这个问题的目标是让 Solid 在 TypeScript 中更有用。
我尝试了什么:我已经对此进行了几个星期的修改,但没有成功。 2.9 release note 提到映射类型 { [P in K]: XXX } 现在也支持符号,但我不知道它在语法上的外观。
export type Wrapped<T> = {
[P in keyof T]: T[P];
} & {
[symbol in keyof T]?: T[symbol]; // doesn't work
} & { _state: number }
“工作”是将包装器编写为
export type Wrapped<T> = {
[P in keyof T]: T[P];
} & { _state: number } & {
[Symbol.toPrimitive](hint: "string"): string;
[Symbol.toPrimitive](hint: "default"): string;
[Symbol.toPrimitive](hint: "number"): number;
}
但显然我不想无条件地将这些符号添加到所有包装类型。基本上,我正在寻找表达“如果符号在 T 中,则将其添加到包装类型”的语法。如果这在一般情况下是不可能的,是否至少可以为一组众所周知的符号进行硬编码?
我在 GitHub 上发现了一些可能相关的问题,但作为一个 TypeScript 初学者,我无法理解它们:
【问题讨论】:
标签: typescript