Typescript是否支持互斥类型?

Bri*_*all 13 typescript

我有一个带参数的方法.我希望Typescript验证传入的对象(在typescript编译时,我理解运行时是一个不同的动物)只满足一个允许的接口.

例:

interface Person {ethnicity: string;}
interface Pet {breed: string;}
function getOrigin(value: Person ^ Pet){...}

getOrigin({}); //Error
getOrigin({ethnicity: 'abc'}); //OK
getOrigin({breed: 'def'}); //OK
getOrigin({ethnicity: 'abc', breed: 'def'});//Error
Run Code Online (Sandbox Code Playgroud)

我意识到这Person ^ Pet不是有效的Typescript,但这是我认为首先尝试并且看似合理的东西.

Gui*_*lli 10

本期所建议,您可以使用条件类型来编写XOR类型:

type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;
Run Code Online (Sandbox Code Playgroud)

现在您的示例起作用了:

interface Person {ethnicity: string;}
interface Pet {breed: string;}
function getOrigin(value: XOR<Person, Pet>) { /* ... */}

getOrigin({}); //Error
getOrigin({ethnicity: 'abc'}); //OK
getOrigin({breed: 'def'}); //OK
getOrigin({ethnicity: 'abc', breed: 'def'});//Error
Run Code Online (Sandbox Code Playgroud)

  • @ConnorDooley 是的,我做到了。这是不久前的事,所以这里有一个更干净的版本:https://tsplay.dev/wgLpBN (10认同)
  • 那个异或太方便了!如何扩展以支持多种互斥类型?您能否扩展您的答案以支持“XOR&lt;Person, Pet, Car, Tree, ..., House&gt;”? (3认同)
  • 可怕的@tjjfvi...:) (3认同)
  • 人们需要建立一条相应的链(我怀疑它是因为传递性而起作用?!):`type XOR3&lt;S, T, U&gt; = XOR&lt;S, XOR&lt;T, U&gt;&gt;;` (2认同)
  • @maninak 参加聚会有点晚了,但是[这个](https://preview.tinyurl.com/y9wcpxuk)(TS游乐场)将通过 `OneOf&lt;[Person, Pet, Car, Tree, ...,房子]&gt;` (2认同)
  • @tjjfvi 这是你写的吗?当我使用它时,我希望能够归功于创建者:) (2认同)

man*_*nak 5

您可以使用微小的 npm 包 ts-xor专门用于解决此问题。

有了它,您可以执行以下操作:

import { XOR } from 'ts-xor'

interface A {
  a: string
}

interface B {
  b: string
}

let A_XOR_B: XOR<A, B>

A_XOR_B = { a: 'a' }          // OK
A_XOR_B = { b: 'b' }          // OK
A_XOR_B = { a: 'a', b: 'b' }  // fails
A_XOR_B = {}                  // fails
Run Code Online (Sandbox Code Playgroud)

完全披露:我是这个小包的作者。我发现我需要一直从 repo-to-repo 实现 XOR 类型。所以我为我和社区发布了它,这样我也可以使用自述文件和共享的 jsdoc 注释正确地记录它。实现是@Guilherme Agostinelli 从社区分享的内容。