【问题标题】:Trying to implement a function that takes two out of three possible types of arguments尝试实现一个函数,该函数采用三种可能类型的参数中的两种
【发布时间】:2021-10-08 15:18:26
【问题描述】:

我有三种不同的类型

type A = 'a'
type B = 'b'
type C = 'c'

我想输入一个函数,要么接受 ACBC,但不接受 ABC

这是我的尝试

type A = 'a'
type B = 'b'
type C = 'c'
type BaseArgs = {
    c: C
}
type VariantA = {
    a: A
} & BaseArgs

type VariantB = {
    b: B,
} & BaseArgs

function fn(arg: VariantA | VariantB) {
}

但事实证明它并没有按预期工作,因为

const b: B = 'b'
const a: A = 'a'
const c: C = 'c'

fn({b,a,c})  // this would not error out

fn({b,a,c}) 应该给出错误,但事实并非如此。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    为了实现所需的行为,您应该将联合类型包装在 StrictUnion 助手中:

    // credits goes to https://stackoverflow.com/questions/65805600/type-union-not-checking-for-excess-properties#answer-65805753
    type UnionKeys<T> = T extends T ? keyof T : never;
    type StrictUnionHelper<T, TAll> =
        T extends any
        ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
    
    type StrictUnion<T> = StrictUnionHelper<T, T>
    
    
    type A = 'a'
    type B = 'b'
    type C = 'c'
    
    type BaseArgs = {
        c: C
    }
    
    type VariantA = {
        a: A
    } & BaseArgs
    
    type VariantB = {
        b: B,
    } & BaseArgs
    
    function fn(arg: StrictUnion<VariantA | VariantB>) {}
    
    
    const b: B = 'b'
    const a: A = 'a'
    const c: C = 'c'
    
    fn({ a, c }) // ok
    fn({ b, c }) // ok
    
    fn({ b, a, c })  // this would not error out
    

    Playground

    fn({ b, a, c }) 此处没有错误,因为此参数可分配给两种联合类型。

    【讨论】:

      【解决方案2】:

      TypeScript 似乎在这里很好——该对象既是有效的 VariantAVariantB,所以它允许它,尽管如果你要“选择”一个或另一个,它有一个额外的变量。如果你不想这样,你可以明确指定:

      type VariantA = {
          a: A;
          b?: never; // This line!
      } & BaseArgs
      

      (对VariantB做同样的事情)

      【讨论】:

        【解决方案3】:

        {a:A, b:B, c:C} 匹配您可接受类型的联合。

        使用重载来指定你只需要一个或另一个:

        function fn(arg: VariantA): void;
        function fn(arg: VariantB): void;
        function fn(arg: VariantB | VariantA) {
        }
        

        typscript playground

        【讨论】:

          猜你喜欢
          • 2018-06-08
          • 2020-10-23
          • 1970-01-01
          • 1970-01-01
          • 2023-02-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多