从Typescript中删除复杂类型的属性

huangapple go评论63阅读模式
英文:

Remove property from a complex type in Typescript

问题

Type T 被定义为一个包含属性 ab,以及要么 c 要么 d 的对象,但不包含两者。我尝试使用 ExcludeOmit,正如你在上面看到的,都不能提供我所需要的结果。

有没有一种方法可以从类型 T 中移除一个属性,同时保持其余部分的结构不变,而不需要预先知道类型 T 的结构?

这个问题与 https://stackoverflow.com/questions/57103834/typescript-omit-a-property-from-all-interfaces-in-a-union-but-keep-the-union-s 中的问题不同:

  • 该类型不是一个简单的联合类型,而是包含一个联合类型的交叉类型。
  • 它还解决了从一个任意的“黑盒”类型中移除属性,而不改变其它语义的问题。
英文:

Consider the following:

type U = {a: string, b: string};

type T = U & ({c: string, d?: never}|{c?: never, d: string});
type E = Exclude<T, {a: string}>;
type O = Omit<T, "a">;

const t1: T = {a: "a", b: "b", c: "c", d: "d"}; // error - expected
const t2: T = {a: "a", b: "b", c: "c"}; // ok - expected
const t3: T = {a: "a", b: "b", d: "d"}; // ok - expected

const e1: E = {b: "foo", c: "c", d: "d"}; // error - expected
const e2: E = {b: "foo", c: "c"}; // error: E is never
const e3: E = {b: "foo", d: "d"}; // error: E is never

const o1: O = {b: "foo", c: "c", d: "d"}; // ok - unexpected!
const o2: O = {b: "foo", c: "c"}; // ok
const o3: O = {b: "foo", d: "d"}; // ok

Type T is defined as a object containing properties a and b and either c or d, but not both.

I am trying to construct a type that is identical to T except it doesn’t have the a property. I tried both Exclude and Omit, as it is evident from the above, neither gives me what I need.

Is there a way to remove a property from a black box type T and keep everything else about it the same without knowing the structure of type T in advance?

Also Typescript playground here.

Edit: Fixed the original type; added more test usages

Edit #2: This question is different from https://stackoverflow.com/questions/57103834/typescript-omit-a-property-from-all-interfaces-in-a-union-but-keep-the-union-s because:

  • The type in question is not a straight union but rather an intersection containing a union on one side
  • It also addresses the issue of removing a property of from an arbitrary “black box” type without changing any other semantics of it.

答案1

得分: 1

对于简单类型(不需要联合类型或其他复杂组合的类型),`Omit` 和 `Exclude` 都可以正常工作。
当基本类型包含联合类型时,在 TypeScript 中称为 [分布式条件类型](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types)。
根据提供的 Playground,一个可工作的示例如下:
```typescript
type DistributiveOmit<T, K extends keyof any> = T extends any
? Omit<T, K>
: never;
type U = {a: string, b: string};
type T = U & ({c: string, d?: never}|{c?: never, d: string});
type D = DistributiveOmit<T, "a">;
const d1: D = {b: "foo", c: "c", d: "d"}; // 错误 - 预期的结果
const d2: D = {b: "foo", c: "c"}; // 正确
const d3: D = {b: "foo", d: "d"}; // 正确

您可以在 Playground 这里 看到它的工作示例。


<details>
<summary>英文:</summary>
Both `Omit` and `Exclude` work fine over simple types (types that do not require unions or other complex compositions)
When the base type contains unions, it is called [Distributive conditional types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types) in typescript
A working example, following the playground provided would look something like this:
```typescript
type DistributiveOmit&lt;T, K extends keyof any&gt; = T extends any
? Omit&lt;T, K&gt;
: never;
type U = {a: string, b: string};
type T = U &amp; ({c: string, d?: never}|{c?: never, d: string});
type D = DistributiveOmit&lt;T, &quot;a&quot;&gt;;
const d1: D = {b: &quot;foo&quot;, c: &quot;c&quot;, d: &quot;d&quot;}; // error - expected
const d2: D = {b: &quot;foo&quot;, c: &quot;c&quot;}; // ok
const d3: D = {b: &quot;foo&quot;, d: &quot;d&quot;}; // ok

You can see it working in Playground here

huangapple
  • 本文由 发表于 2023年6月8日 08:48:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427947.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定