繁体   English   中英

如何定义不包含特定成员的对象类型

[英]How to define an object type that does _not_ include a specific member

我正在处理我放入和退出数据库/动作的对象,有时希望添加和删除特定于数据库/动作的字段。

例如,我有:

type EntryEvent<EntryLine> = { type: 'entry' } & EntryLine;

在其他地方,我希望删除type成员,以便将EntryEvent<EntryLine>EntryLine 为此,我使用以下实用程序函数:

export function stripFields<T extends object, K extends keyof T>(
  o: T,
  fields: K[]
): Omit<T, K> {
  const result: Partial<T> = { ...(<object>o) };
  for (const field of fields) {
    delete result[field];
  }
  return <Omit<T, K>>result;
}

麻烦的是,生成的对象将不会被识别为EntryLine

如果我尝试将以下内容分配给EntryLine类型:

stripFields(event, ['type'])

我会得到:

Argument of type 'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is not assignable to parameter of type 'EntryLine'.
  'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is assignable to the constraint of type 'EntryLine', but 'EntryLine' could be instantiated with a different subtype of constraint 'Pick<object, never>' ts(2345)

据我所知,这是有道理的,因为如果通用类型EntryLine包含type成员,则stripFields的结果将不再是EntryLine (因为它将丢失其type成员)。

有什么方法可以定义约束通用类型EntryLine以便它不允许带有type字段的对象? 还是有其他解决方法?

更新:

以下代码为我重现了该问题:

type EntryEvent<EntryLine> = { type: "entry" } & EntryLine;

type MyEntryLine = {
  a: Date;
};

export function stripFields<T extends object, K extends keyof T>(
  o: T,
  fields: K[]
): Omit<T, K> {
  const result: Partial<T> = { ...(<object>o) };
  for (const field of fields) {
    delete result[field];
  }
  return <Omit<T, K>>result;
}

type Callback<EntryLine> = (a: EntryLine) => void;

function thingThatTakesAnEvent<EntryLine>(a: EntryEvent<EntryLine>, callback: Callback<EntryLine>) {
  callback(stripFields(a, ["type"]));
}

function thingThatTakesAMyEntryLine(a: MyEntryLine) {
  console.log(a.a);
}

declare let event: EntryEvent<MyEntryLine>;

thingThatTakesAnEvent(event, thingThatTakesAMyEntryLine);

这里的游乐场

“ Pick <EntryEvent <EntryLine>,Exclude <EntryLine的键,“类型” >>”可分配给类型“ EntryLine”的约束,但是可以使用约束“ {}”的另一个子类型实例化“ EntryLine”。

这种形式的错误消息基本上意味着,您试图从传入的泛型类型参数中推断出太多信息,而泛型类型参数只有调用者/客户端才能知道。 Typescript不再认为您对它的类型的猜测是安全的。

关于您的代码,可以将其翻译为:

function thingThatTakesAnEvent<EntryLine>(
  a: EntryEvent<EntryLine>,
  callback: Callback<EntryLine>
) {
  callback(stripFields(a, ["type"]));
           //------ error ------//
}

==> stripFields的返回类型为Pick< EntryEvent< EntryLine>, Exclude< keyof EntryLine, "type">> ,可以分配给约束EntryLine (默认为{} ),但是如果调用者调用了该方法像这样的函数: thingThatTakesAnEvent<{foo: "bar"}> 在函数内部,我们不知道它是{foo: "bar"} ,我们应该使用EntryLine调用callback ,但是我们使用了特定的子类型,这可能与调用者不EntryLine

根据目的,您可以执行以下操作:

  1. 更改您的回调类型以匹配stripFields Playground的类型:
type Callback<EntryLine> = (a: Omit<EntryEvent<EntryLine>, "type">) => void;
  1. thingThatTakesAndEvent Playground中进行转换
function thingThatTakesAnEvent<EntryLine>(
  a: EntryEvent<EntryLine>,
  callback: Callback<EntryLine>
) {
  callback((stripFields(a, ["type"]) as unknown) as EntryLine);
}

暂无
暂无

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

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