- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
遵循 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/
前段时间翻到几条留言,问: “配置即代码和基础设施即代码一样吗?” “配置即代码是什么?怎么都是基础设施即代码?” 我们都是知道,DevOp的快速发展,让服务器管理与配置的时间大大减少,配置即代
我是否应该始终将/.well-known/acme-challenge暴露在服务器上? 这是我的HTTP配置: server { listen 80; location '/.well-known
假设我运行请求GET https://graph.microsoft.com/v1.0/me/messages 我得到了 Message 对象的列表。根据文档here id (string) - Un
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 8 年前。 Improv
给定的问题: 给定一个有 n 行、m 个座位的剧院,以及一个已预订座位的列表。给定这些值,确定有多少种方式可以让两个 friend 坐在同一排。 因此,如果剧院的大小为 2x3,并且第一排的第一个座位
通常,对于 OIDC 发现,.well-known URI 可以作为匿名请求。 WSO2 5.3.0 文档中的示例指出必须为请求提供管理员级凭据: https://docs.wso2.com/disp
我是identityserver4的新手,最近看到identityserver团队提供的Quickstart8示例,里面包含3个项目 1.Identityserver2. Api 3.当我部署到 ii
我是一名优秀的程序员,十分优秀!