【问题标题】:Generic type inference from an specific function argument来自特定函数参数的通用类型推断
【发布时间】:2021-11-01 00:07:42
【问题描述】:

如何让 TS 从多个参数之间的特定函数参数推断类型?

type TypeA<T extends string> = Record<T, unknown>;
type TypeB<T> = { array: T[] };

function fn<T extends string>(a: TypeA<T>, b: TypeB<T>): void {}

fn(
    {
        attr1: 1,
        attr2: 2,
    },
    {
        array: ["attr1"],
    }
);

在此示例中,TS 抱怨第一个参数中的属性 attr2

Argument of type '{ attr1: number; attr2: number; }' is not assignable to parameter of type 'TypeA<"attr1">'.
  Object literal may only specify known properties, but 'attr2' does not exist in type 'TypeA<"attr1">'. Did you mean to write 'attr1'?ts(2345)

这意味着 T 是从数组中推断出来的,但我想要完成的是 T 从第一个参数中推断出来,这是对象的键。 T 应改为 "attr1" | "attr2"

我该如何做到这一点?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    你还需要推断a参数:

    type TypeA<T extends string> = Record<T, unknown>;
    type TypeB<T> = { array: T[] };
    
    function fn<T extends string, Rec extends TypeA<T>>(a: Rec, b: TypeB<T>): void { }
    
    fn(
      {
        attr1: 1,
        attr2: 2,
      },
      {
        array: ["attr1", 'attr2'], // ok
      }
    );
    
    fn(
      {
        attr1: 1,
        attr2: 2,
      },
      {
        array: ["attr12"], // expected error
      }
    );
    

    Playground

    你可以在我的blog找到更多关于函数参数推断的信息

    更新

    在操场上,TS 抱怨第一个参数的 attr1 第二次 fn 调用,而不是您预期的数组值 我的错,

    type TypeA<T extends string> = Record<T, unknown>;
    type TypeB<T> = { array: T[] };
    
    function fn<
      T extends string,
      Rec extends TypeA<T>,
      Arr extends Array<keyof Rec>
    >(a: Rec, b: { array: [...Arr] }): void { }
    
    fn(
      {
        attr1: 1,
        attr2: 2,
      },
      {
        array: ["attr1", 'attr2'], // ok
      }
    );
    
    fn(
      {
        attr1: 1,
        attr2: 2,
      },
      {
        array: ["attr12"], // expected error
      }
    );
    

    Playground

    【讨论】:

    • 在操场上,TS 抱怨的是第二个 fn 调用的第一个参数的 attr1,而不是您预期的数组值。
    • @MateusPires 好点,我更新了
    【解决方案2】:

    也许这就是你想要达到的目标:

    function fn<T, K extends keyof T>(a:T, b: { array: K[] }): void {}
    
    fn(
        {
            attr1: 1,
            attr2: 2,
        },
        {
            array: ["attr1"], // ok
        }
    );
    
    fn(
        {
            attr1: 1,
            attr2: 2,
        },
        {
            array: ["attr1", "attr3"], // Type '"attr3"' is not assignable to type '"attr1" | "attr2"'.
        }
    );

    【讨论】:

      【解决方案3】:

      其他答案的替代方案:

      type TypeA<T extends string> = Record<T, unknown>;
      type TypeB<T> = { array: T[] };
      
      function fn<
        T extends string,
        V extends TypeA<T>
      >(
        a: V,
        b: TypeB<keyof V>
      ): void { }
      
      fn(
        {
          attr1: 1,
          attr2: 2,
        },
        {
          array: ["attr1"],
        }
      );
      
      fn(
        {
          attr1: 1,
          attr2: 2,
        },
        {
          array: ["attr3"], // Type '"attr3"' is not assignable to type '"attr1" | "attr2"'.
        }
      );
      

      Playground

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-26
        • 2011-06-27
        • 1970-01-01
        • 2020-03-01
        • 2013-11-10
        • 2020-10-31
        • 2021-04-06
        • 1970-01-01
        相关资源
        最近更新 更多