简体   繁体   English

在 Typescript 中删除对象键并返回条件类型

[英]Delete object keys and return conditional type in Typescript

I have two interfaces to describe the different messages我有两个接口来描述不同的消息

interface MessageA {
  timestamp: number
}

interface MessageB {
  name: string
}

and an interface to describe their common fields和一个接口来描述他们的共同领域

interface CommonMessage {
  text: string
  url: string
}

And I combine them into a new type by adding extra fields with the type declared using const enum我通过添加使用const enum声明的类型的额外字段将它们组合成一个新类型

const enum Type {
  A,
  B,
}

type CombinedMessage =
  | (MessageA & CommonMessage & { type: Type.A })
  | (MessageB & CommonMessage & { type: Type.B })

Besides, I define a type that removes the common fields in the CombinedMessage此外,我定义了一个类型,它删除了CombinedMessage中的公共字段

type DistributiveOmit<T, K extends string & keyof T> = T extends any ? Omit<T, K> : never
type Message = DistributiveOmit<CombinedMessage, keyof CommonMessage | 'type'>

Now, I want to define a function to convert CombinedMessage into Message .现在,我想定义一个函数来将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
}

After omit function is defined, I can define定义omit函数后,我可以定义

function removeCommonFields(combinedMessage: CombinedMessage): Message {
  return omit(combinedMessage, ['text', 'url', 'type'])
}

to get what I want.得到我想要的。

However, Typescript compiler shows that the line但是, Typescript编译器显示该行

return ret

in function omit has errors that在函数中omit有错误

Type 'T' is not assignable to type 'DistributiveOmit<T, K>'.ts(2322)

It shows that ret here is the generic type T , so I cannot return as the type DistributiveOmit<T, K> .它表明这里的ret是泛型类型T ,所以我不能作为DistributiveOmit<T, K>类型返回。

It seems that delete operation do nothing for the type of ret .似乎delete操作对ret类型没有任何作用。

Currently, I use return ret as unknown as DistributiveOmit<T, K> to avoid the compiler showing error;目前,我使用return ret as unknown as DistributiveOmit<T, K>来避免编译器显示错误; however, I want to avoid using type assertion as possible as I can.但是,我想尽可能避免使用类型断言。

Is there any other ideas?还有其他想法吗? Thanks.谢谢。

This is more or less a design limitation of TypeScript.这或多或少是 TypeScript 的设计限制。 You can't really avoid type assertions here.在这里您无法真正避免类型断言

The compiler defers evaluation of conditional types that depend on an as-yet-unspecified generic type parameters, and thus it cannot really verify that anything is assignable to such types.编译器推迟对依赖于尚未指定的泛型类型参数的条件类型的评估,因此它无法真正验证任何东西都可以分配给这些类型。

And while Omit<X, K> is seen as a supertype of X , and thus Omit<X, K> | Omit<Y, K> | Omit<Z, K>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> would be seen as a supertype of X | Y | Z Omit<X, K> | Omit<Y, K> | Omit<Z, K>将被视为X | Y | Z的超类型X | Y | Z X | Y | Z , the compiler does not know how to generalize that distributivity to DistributiveOmit<T, K> inside the body of omit() where T is unspecified. X | Y | Z ,编译器不知道如何将该分布推广到DistributiveOmit<T, K>omit()的主体内,其中T未指定。

There is an open feature request at microsoft/TypeScript#33912 asking for more compiler support with generic functions that return conditional types. microsoft/TypeScript#33912 上有一个开放功能请求,要求为返回条件类型的泛型函数提供更多编译器支持。 It doesn't look like there's any obvious solution to this in the near future, and even if there were it might not work in your particular example.看起来在不久的将来没有任何明显的解决方案,即使有它在您的特定示例中也可能不起作用。 So for the time being, the best you can do is a type assertion (or something equivalent like a single call-signature overload ).因此,就目前而言,您能做的最好的事情是类型断言(或类似单个调用签名重载的等效内容)。


The only slight improvement I can think of would be to use Omit<T, K> instead of unknown as your intermediate asserted type:我能想到的唯一轻微改进是使用Omit<T, K>而不是unknown作为您的中间断言类型:

return ret as Omit<T, K> as DistributiveOmit<T, K>; // no error

It would help catch errors where you return something other than ret accidentally:这将有助于捕获您意外返回ret以外的其他内容的错误:

// return "oopsie" as unknown as DistributiveOmit<T, K>; // no error
// return "oopsie" as Omit<T, K> as DistributiveOmit<T, K>; // error!

Which might be better than nothing, but not by much.这可能总比没有好,但也好不了多少。

Playground link to code Playground 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM