【问题标题】:TypeScript interface with XOR, {bar:string} xor {can:number} [duplicate]TypeScript 接口与 XOR,{bar:string} xor {can:number} [重复]
【发布时间】:2017-11-09 13:21:02
【问题描述】:

我如何说我想要一个界面是一个或另一个,但不是两者兼而有之?

interface IFoo {
    bar: string /*^XOR^*/ can: number;
}

【问题讨论】:

    标签: typescript interface schema xor typescript2.0


    【解决方案1】:

    您可以使用联合类型和 never 类型来实现此目的:

    type IFoo = {
      bar: string; can?: never
    } | {
        bar?: never; can: number
      };
    
    
    let val0: IFoo = { bar: "hello" } // OK only bar
    let val1: IFoo = { can: 22 } // OK only can
    let val2: IFoo = { bar: "hello",  can: 22 } // Error foo and can
    let val3: IFoo = {  } // Error neither foo or can
    

    【讨论】:

    • 太棒了!我从来没有意识到never 可以用来禁止密钥出现!
    • 太好了,这就是我所追求的。 +1 & 接受
    • @AT 不被接受
    • @godblessstrawberry 我的错! - 接受。
    • 这项工作不应该:let val2: IFoo = { bar: "hello", can: undefined }
    【解决方案2】:

    this issue 中所建议,您可以使用conditional types (introduced in Typescript 2.8) 编写一个异或类型:

    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;
    

    你可以像这样使用它:

    type IFoo = XOR<{bar: string;}, {can: number}>;
    let test: IFoo;
    test = { bar: "test" } // OK
    test = { can: 1 } // OK
    test = { bar: "test",  can: 1 } // Error
    test = {} // Error
    

    【讨论】:

    • 花式.....................................
    • 两种以上类型的XOR&lt;A | B | C | D&gt; 怎么样?
    • @trusktr 我认为结合 TS3.1 可以归结为 variadic generics。不幸的是,我自己还没有想出解决方案。但我可以考虑使用 Head、Tail、HasTail 和递归,如下所示:freecodecamp.org/news/typescript-curry-ramda-types-f747e99744ab。不利的一面是,这不会检查置换集,我不知道这是否与集合论中的运算(例如三角不等式)发生冲突。
    【解决方案3】:

    您可以通过 union 和可选的void type 获得“一个而不是另一个”:

    type IFoo = {bar: string; can?: void} | {bar?:void; can: number};
    

    但是,您必须使用 --strictNullChecks 来防止两者都没有。

    【讨论】:

      【解决方案4】:

      试试这个:

      type Foo = {
          bar?: void;
          foo: string;
      }
      
      type Bar = {
          foo?: void;
          bar: number;
      }
      
      type FooBar = Foo | Bar;
      
      // Error: Type 'string' is not assignable to type 'void'
      let foobar: FooBar = {
          foo: "1",
          bar: 1
      }
      
      // no errors
      let foo = {
          foo: "1"
      }
      

      【讨论】:

        猜你喜欢
        • 2017-06-01
        • 2018-08-19
        • 2014-01-17
        • 2022-09-22
        • 2014-09-15
        • 1970-01-01
        • 2017-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多