根据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>
的{{1}},只要嵌套状态下的某个地方出现诸如{{1 }},导致MyState
的转换到处都是。这个问题的目的是使TypeScript更加实用。
我尝试过的事情:我已经对此进行了几周的修改,但没有成功。 2.9 release note提到映射类型Date
现在也支持符号,但是我不知道它在语法上的外观。
... as any as X
“工作原理”是将包装器写为
{ [P in K]: XXX }
但是显然我不想无条件地将这些符号添加到所有包装的类型中。基本上,我正在寻找表示“如果符号在T中,请将其添加到包装的类型中”的语法。如果通常无法做到这一点,那么是否至少可以对一组知名符号进行硬编码?
我在GitHub上发现了一些可能相关的问题,但是作为TypeScript的初学者,我对它们没有多大意义:
答案 0 :(得分:2)
您可以使用conditional types
dict
更新 @jcalz
提出了一个简短的解决方案type AddSymbolToPrimitiveDefault<T> = T extends
{[Symbol.toPrimitive](hint: "default"): string;} ?
{[Symbol.toPrimitive](hint: "default"): string;} : {};
type AddSymbolToPrimitiveString<T> = T extends
{[Symbol.toPrimitive](hint: "string"): string;} ?
{[Symbol.toPrimitive](hint: "string"): string;} : {};
type AddSymbolToPrimitiveNumber<T> = T extends
{[Symbol.toPrimitive](hint: "number"): number;} ?
{[Symbol.toPrimitive](hint: "number"): number;} : {};
type AddSymbolToPrimitiveTString<T> = T extends
{[Symbol.toPrimitive](hint: string): string | number;} ?
{[Symbol.toPrimitive](hint: string): string | number;} : {};
export type Wrapped<T> = {
[P in keyof T]: T[P];
} & { _state: number } & AddSymbolToPrimitiveDefault<T>
& AddSymbolToPrimitiveString<T> & AddSymbolToPrimitiveNumber<T> & AddSymbolToPrimitiveTString<T>
function wrap<T extends object>(x: T): Wrapped<T> {
let xWrapped = x as Wrapped<T>
xWrapped._state = 0;
return xWrapped;
}
let a = new Date()
let b = wrap(a);
function f(d: Date) {}
f(a); // works
f(b); // works too
答案 1 :(得分:1)
问题是well-known symbols are not included as part of keyof
,因此您无法映射它们。该问题被混淆地标记为“已解决”,但是我认为这是一个错误或误导;其也标记为“可用的修复程序”,这是正确的:this pull request应该解决合并后的问题。这里的活动看起来足够新(2019年6月),因此在不远的将来有一定的机会用该语言查看该活动,但是您可能想继续研究这些问题并给它们?或描述您的用例,如果您认为它们特别引人注目。
对于您来说,我没有一个很好的解决方法,因为目前很难检测到这些知名的符号键。如果您进行任何特殊包装,它可能必须是将这些符号作为键的类型,而不是键本身。哦,好吧。编辑:@NailAchmedzhanov的answer对我来说似乎是一个可行的解决方法。
无论如何,希望能有所帮助;祝你好运!