![](/img/trans.png)
[英]How to define a conditional return type based on if an object property is set in Typescript
[英]Delete object keys and return conditional type in Typescript
我有两个接口来描述不同的消息
interface MessageA {
timestamp: number
}
interface MessageB {
name: string
}
和一个接口来描述他们的共同领域
interface CommonMessage {
text: string
url: string
}
我通过添加使用const enum
声明的类型的额外字段将它们组合成一个新类型
const enum Type {
A,
B,
}
type CombinedMessage =
| (MessageA & CommonMessage & { type: Type.A })
| (MessageB & CommonMessage & { type: Type.B })
此外,我定义了一个类型,它删除了CombinedMessage
中的公共字段
type DistributiveOmit<T, K extends string & keyof T> = T extends any ? Omit<T, K> : never
type Message = DistributiveOmit<CombinedMessage, keyof CommonMessage | 'type'>
现在,我想定义一个函数来将CombinedMessage
转换为Message
。
const omit = <T, K extends string & keyof T>(value: T, keys: readonly K[]): DistributiveOmit<T, K> => {
const ret = { ...value }
for (const key of keys) {
delete ret[key]
}
return ret
}
定义omit
函数后,我可以定义
function removeCommonFields(combinedMessage: CombinedMessage): Message {
return omit(combinedMessage, ['text', 'url', 'type'])
}
得到我想要的。
但是, Typescript
编译器显示该行
return ret
在函数中omit
有错误
Type 'T' is not assignable to type 'DistributiveOmit<T, K>'.ts(2322)
它表明这里的ret
是泛型类型T
,所以我不能作为DistributiveOmit<T, K>
类型返回。
似乎delete
操作对ret
类型没有任何作用。
目前,我使用return ret as unknown as DistributiveOmit<T, K>
来避免编译器显示错误; 但是,我想尽可能避免使用类型断言。
还有其他想法吗? 谢谢。
这或多或少是 TypeScript 的设计限制。 在这里您无法真正避免类型断言。
编译器推迟对依赖于尚未指定的泛型类型参数的条件类型的评估,因此它无法真正验证任何东西都可以分配给这些类型。
而Omit<X, K>
被视为X
的超类型,因此Omit<X, K> | Omit<Y, K> | Omit<Z, K>
Omit<X, K> | Omit<Y, K> | Omit<Z, K>
Omit<X, K> | Omit<Y, K> | Omit<Z, K>
将被视为X | Y | Z
的超类型X | Y | Z
X | Y | Z
,编译器不知道如何将该分布推广到DistributiveOmit<T, K>
在omit()
的主体内,其中T
未指定。
microsoft/TypeScript#33912 上有一个开放功能请求,要求为返回条件类型的泛型函数提供更多编译器支持。 看起来在不久的将来没有任何明显的解决方案,即使有它在您的特定示例中也可能不起作用。 因此,就目前而言,您能做的最好的事情是类型断言(或类似单个调用签名重载的等效内容)。
我能想到的唯一轻微改进是使用Omit<T, K>
而不是unknown
作为您的中间断言类型:
return ret as Omit<T, K> as DistributiveOmit<T, K>; // no error
这将有助于捕获您意外返回ret
以外的其他内容的错误:
// return "oopsie" as unknown as DistributiveOmit<T, K>; // no error
// return "oopsie" as Omit<T, K> as DistributiveOmit<T, K>; // error!
这可能总比没有好,但也好不了多少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.