【问题标题】:It it possible to infer function generic type based on all rest arguments?是否可以根据所有其余参数推断函数泛型类型?
【发布时间】:2020-03-09 00:11:48
【问题描述】:

我有类似下面的代码:

type Boxed<T> = { inner: T }

const box = <T>(inner: T): Boxed<T> => ({ inner });

function test<T extends Boxed<any>>(...args: T[]): T extends Boxed<infer I> ? I : never {
    return args[0].inner;
}

这里,Boxed&lt;T&gt; 代表一些复杂的泛型类型,该函数旨在根据所有输入有效地将其输入“拆箱”为联合类型的某个值。但是,如果我们只是传入我们需要的值,则类型 T 会被推断为第一个参数的类型,而所有其他参数都将被拒绝:

test(box(0), box('str'));
// Argument of type 'Boxed<string>' is not assignable to parameter of type 'Boxed<number>'.

同时,通过解构元组来传递这个参数也可以正常工作:

test(...[box(0), box('str')]);
// Works and has an expected type (string | number).

我可以对函数定义做些什么,以便第一个(显然更符合人体工程学的)示例也可以工作吗?

Playground Link

【问题讨论】:

    标签: typescript generics type-inference


    【解决方案1】:

    当类型参数 T 具有数组类型约束 &lt;T extends Boxed&lt;any&gt;[]&gt; 而不是项约束时,编译器会正确推断 generic rest parameters 的元组类型:

    type Boxed<T> = { inner: T }
    
    const box = <T>(inner: T): Boxed<T> => ({ inner });
    
    // here 'extends Boxed<any>[]' instead of 'extends Boxed<any>'
    function test<T extends Boxed<any>[]>(...args: T): T extends Boxed<infer I>[] ? I : never {
        return args[0].inner;
    }
    
    test(box(0), box('str')); // string | number ?
    test(...[box(0), box('str')]); // string | number ?
    

    Playground

    如果你写成T extends Boxed&lt;any&gt;&gt;(...args: T[]),TS 显然渴望通过第一项的类型来推断整个数组类型,因为所有其余参数项都应该具有相同的类型。

    declare function foo<T extends string | number>(...args: T[]): void
    // foo<"bar">(...args: "bar"[]): void;
    foo("bar", 1) // nono, '1' is not assignable to parameter of type '"bar"'
    

    这种表示法正确地解析了通用的剩余参数。

    declare function foo2<T extends (string | number)[]>(...args: T): void
    // foo2<["bar", 1]>(args_0: "bar", args_1: 1): void
    foo2("bar", 1)
    

    【讨论】:

      猜你喜欢
      • 2020-01-25
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 2020-03-12
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      相关资源
      最近更新 更多