【问题标题】:Removing properties from an object but preserving type从对象中删除属性但保留类型
【发布时间】:2021-04-19 00:03:46
【问题描述】:

假设我有一个任意对象:

const foo = {foo: 1, bar: 2, baz: 3};

我想删除 bar 属性。我可以使用如下函数来做到这一点:

function omission<T extends {}, K extends keyof T = keyof T>(
  obj: T,
  remove: K
): Omit<T, K> {
  const { [remove]: _, ...without } = obj;
  return without;
}

这确实从类型系统和运行时系统中删除了一个属性。耶。但我希望能够删除任意数量的道具。我希望一点递归可以解决问题,但我正在努力让它发挥作用。这是我的尝试:

export function omit<T extends {}, K extends keyof T = keyof T>(
  obj: T,
  ...removals: K[]
) {
  if (removals.length === 0) {
    return obj;
  }
  const omitted = omission(obj, removals[0]);
  const remaining = (removals.slice(1) as unknown) as Array<keyof typeof omitted>;

  return remaining.length > 0 ? omit(omitted, remaining) : omitted;
}

毫不奇怪,它确实在运行时系统中工作,但类型系统放弃了。诚然,我的强制打字尝试是绝望的,但我很绝望。有谁知道如何把这个工具从车库里拿出来?

Playground Link

【问题讨论】:

  • 除了接受每种类型作为单独的参数之外,我想不出任何可能的方法。 See this
  • 作为选项removals.reduce((a:Omit&lt;T, K&gt; ,c) =&gt;{ const { [c]: _, ...without } = a; return without as Omit&lt;T, K&gt;}, obj)

标签: typescript


【解决方案1】:

鉴于键是完全动态的,我认为没有使用类型断言somewhere的方法可以做到这一点。

我认为不是递归,而是通过键数组是否包含键来过滤对象的条目,然后使用Object.fromEntries将其转回对象。

function omit<T extends {}, K extends Array<keyof T>>(
  obj: T,
  ...removals: K
) {
  // workaround for TypeScript's bad .includes typing:
  // https://github.com/microsoft/TypeScript/issues/26255
  const removalsUntyped = removals as Array<unknown>;
  return Object.fromEntries(
    Object.entries(obj)
      .filter(([key]) => !removalsUntyped.includes(key))
  ) as Omit<T, K[number]>;
}

const foo = { foo: 1, bar: 2, baz: 3 };
const reduced = omit(foo, 'bar', 'baz');
console.log(reduced);

【讨论】:

  • 太棒了!像魅力一样工作。
猜你喜欢
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 2018-01-17
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
相关资源
最近更新 更多