gpt4 book ai didi

typescript - 如何在类型包装器(映射类型)中转发(众所周知的)符号?

转载 作者:搜寻专家 更新时间:2023-10-30 21:25:29 24 4
gpt4 key购买 nike

遵循 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 , 导致 ... as any as X无处不在。这个问题的目的是让 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 的初学者,我无法理解它们:

最佳答案

您可以使用 conditional types

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

更新@jcalz 建议的简短解决方案

type AddSymbolToPrimitive<T> = T extends 
{[Symbol.toPrimitive]: infer V;} ?
{[Symbol.toPrimitive]: V;} : {};

export type Wrapped<T> = {
[P in keyof T]: T[P];
} & { _state: number } & AddSymbolToPrimitive<T>

关于typescript - 如何在类型包装器(映射类型)中转发(众所周知的)符号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57100616/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com