类型保护和扩展联合类型?

type guards and extending a union type?

我有一个对象数组,其中每个项目都扩展了 {x: method}{y: method},我想尝试将它们分开。我写了以下内容

export const refresh = <
  N extends HasRefresh | HasRefreshWithFoo,
  RefreshWithFoo extends HasRefreshWithFoo,
  RefreshNormal extends HasRefresh
>(
  ns: N[],
  foos: Foo[]
) => {
  const refreshWithFoo: RefreshWithFoo = ns.filter((n): n is RefreshWithFoo  =>
    n.x !== undefined
  ) 
}

但是我收到了错误

A type predicate's type must be assignable to its parameter's type.
  Type 'RefreshNormal' is not assignable to type 'N'.

给定一组包含扩展 HasRefreshWithFoo 或扩展 HasRefresh 的项目的对象,我如何将数组与并集分开,以便我有一个仅包含 RefreshNormal 的数组和一个仅包含 RefreshWithFoo 的数组?

您可以通过对泛型类型进行另一种抽象来缩小编译器错误。
第二个抽象负责按给定类型过滤数组。

const filterByType = <T>(arr: any[], key: keyof T): T[] =>
    arr.filter(e => (<T>e)[key]) as T[];

Typescript guide of how to type guard an instance 之后,我们必须指定要检查转换是否有效完成的键(我们过滤所依据的类型中的唯一键)。

因此,我们现在可以通过 RefreshWithFoo

在我们的函数中进行过滤
export const refresh = <
  N extends HasRefresh | HasRefreshWithFoo,
  RefreshWithFoo extends HasRefreshWithFoo,
  RefreshNormal extends HasRefresh
>(
    ns: N[], 
    foos: Foo[]
) => {
    const refreshWithFoo: RefreshWithFoo[] = filterByType<RefreshWithFoo>(ns, `x`);
}

没有任何编译器抱怨。
好吧,我正在使用默认的 tsconfig,我认为这不会与任何其他编译器配置发生冲突。如果是这样,请告诉我。

编辑
在某些情况下,例如类型交集,您将需要多个键来检查。您可以通过期望键的参数数组并检查所有键来简单地扩展该方法,就像这样

const filterByType = <T>(arr: any[], ...keys: (keyof T)[]): T[] =>
    arr.filter(e => keys.every(k => (<T>e)[k])) as T[];

希望对您有所帮助。