简体   繁体   English

TypeScript 无法解析函数泛型中的元组

[英]TypeScript can't resolve tuple in function generics

I'm trying to use a union type of overloaded functions with generic return type and it seems that TypeScript is lost when a tuple type is passed as a generic:我正在尝试使用具有泛型返回类型的联合类型的重载函数,并且当元组类型作为泛型传递时,TypeScript 似乎丢失了:

type Fn1<R> = (one: string) => R;
type Fn2<R> = (one: string, two: string) => R;
type Fn3<R> = (one: string, two: string, three: string) => R;
type GenericOverloadingFn<R> = Fn1<R> | Fn2<R> | Fn3<R>;

type TupleOfPrimitives = [
  string,
  number
];

type StructWithKeys = {
  one: string;
  two: number;
}

type UnionFn = GenericOverloadingFn<TupleOfPrimitives>
  | GenericOverloadingFn<string>
  | GenericOverloadingFn<StructWithKeys>; 

type UnionGenericFn = GenericOverloadingFn<
  TupleOfPrimitives
  | string
  | StructWithKeys
>; 

const union2Fn0: UnionFn = (one: string, two: string) => "hey"; // works
const union2Fn1: UnionFn = (one: string, two: string) => ({ one: "hey", two: 1 }); // works
const union2Fn2: UnionFn = (one: string, two: string) => ["hey", 2]; // error

const union1Fn0: UnionFn = (one: string) => ["hey", 2]; // error
const union3Fn0: UnionFn = (one: string, two: string, three: string) => ["hey", 2]; // works


const unionGeneric2Fn0: UnionGenericFn = (one: string, two: string) => "hey"; // works
const unionGeneric2Fn1: UnionGenericFn = (one: string, two: string) => ({ one: "hey", two: 1 }); // works
const unionGeneric2Fn2: UnionGenericFn = (one: string, two: string) => ["hey", 2]; // error

const unionGeneric3Fn2: UnionGenericFn = (one: string, two: string, three: string) => ["hey", 2]; // works


const fn20: Fn2<TupleOfPrimitives> = (one: string, two: string) => ["hey", 2]; // works
const fn21: Fn2<string | TupleOfPrimitives> = (one: string, two: string) => "hey"; // works
const fn22: Fn2<string | TupleOfPrimitives> = (one: string, two: string) => ["hey", 2]; // works


const genericOverloading2Fn: GenericOverloadingFn<TupleOfPrimitives> =
  (one: string, two: string) => ["hey", 2]; // error

const genericOverloading3Fn: GenericOverloadingFn<TupleOfPrimitives> =
  (one: string, two: string, three: string) => ["hey", 2]; // works

Errors mostly look like this错误主要是这样的

Type '(one: string, two: string) => (string | number)[]' is not assignable to type 'UnionFn'.
  Type '(one: string, two: string) => (string | number)[]' is not assignable to type 'Fn1<TupleOfPrimitives>'.

I'm not sure if doing something wrong or is it a limitation/bug of TypeScript?我不确定是做错了什么还是 TypeScript 的限制/错误?

The issue here is TypeScript inference, which is wider then your type needs.这里的问题是 TypeScript 推理,它比您的类型需要更广泛。 We can do the simple check, what type has such construct:我们可以做一个简单的检查,什么类型有这样的构造:

const a = ['a', 1];
type A = typeof a; // (string | number)[]

So clearly (string | number)[] is more wide type then [string, number] and there is the issue.很明显(string | number)[]是比[string, number]更宽的类型,这就是问题所在。 To fix it simply we need to apply type assertion:为了简单地修复它,我们需要应用类型断言:

 (one: string) => ['a', 1] as TupleOfPrimitives

Also take into consideration that in the field most probably you will not return const only, but there will be some other function calling, and in this situation probably you will avoid assertion.还要考虑到在现场很可能你不会只返回 const,但会有一些其他的函数调用,在这种情况下你可能会避免断言。 Consider example:考虑示例:

const g = (one: string): TupleOfPrimitives => [one, 1]; 
const f: GenericOverloadingFn<TupleOfPrimitives> = (one: string) => g(one)

Function f does not need to have assertion inside as it is calling function g which clearly defines correct type as a return type.The issue will come only when you will want to put constant value by hand, as you do in your examples.函数f不需要内部断言,因为它正在调用函数g ,它清楚地将正确类型定义为返回类型。只有当您想要手动放置常量值时才会出现问题,就像您在示例中所做的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM