英文:
Remove property from a complex type in Typescript
问题
Type T
被定义为一个包含属性 a
和 b
,以及要么 c
要么 d
的对象,但不包含两者。我尝试使用 Exclude
和 Omit
,正如你在上面看到的,都不能提供我所需要的结果。
有没有一种方法可以从类型 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<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"}; // error - expected
const d2: D = {b: "foo", c: "c"}; // ok
const d3: D = {b: "foo", d: "d"}; // ok
You can see it working in Playground here
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论