简体   繁体   English

使用TypeScript将箭头函数分配给通用函数类型

[英]Assigning arrow function to generic function type with TypeScript

I've done some digging on similar questions but I cannot find a solution that works. 我已经对类似的问题做了一些探讨,但是找不到有效的解决方案。 I've got some types of generic functions, but I cannot seem to implement them correctly. 我有一些通用函数,但是我似乎无法正确实现它们。

In short, I have this: 简而言之,我有这个:

/** Takes three values of the same type and collapses them into one */
declare type MergeFunction = <T>(def: T, file?: T, arg?: T) => T

/** The implementation I'm having trouble with. Merge three arrays of the same type. */
const arrayMerge: MergeFunction = <T>(def: T[], file: T[] = [], arg: T[] = []): T[] => [ ].concat(def).concat(file || [ ]).concat(arg || [ ])

However, I get a compiler error: 但是,出现编译器错误:

Property 'arrayMerge' is incompatible with index signature.
  Type '<A>(def: A[], file?: A[], arg?: A[]) => A[]' is not assignable to type 'MergeFunction'.
    Types of parameters 'def' and 'def' are incompatible.
      Type 'T' is not assignable to type '{}[]'.

How do I actually implement this type? 我实际上如何实现这种类型?

As you've defined it, a function of type MergeFunction must work for any type T that the caller specifies. 如定义的那样,类型MergeFunction的函数必须对调用者指定的任何类型T起作用。 So arrayMerge is not a MergeFunction , since it only accepts arrays. 所以arrayMerge 不是 MergeFunction ,因为它只接受数组。 Here's one way to implement your MergeFunction as specified: 这是按指定方式实现MergeFunction的一种方法:

declare type MergeFunction = <T>(def: T, file?: T, arg?: T) => T;
const returnLastSpecifiedThing: MergeFunction = <T>(def: T, file?: T, arg?: T) =>
  typeof arg !== 'undefined' ? arg : 
  typeof file !== 'undefined' ? file : 
  def;

In fact, the only thing you can safely do when implementing a type like MergeFunction is to return one of the inputs, because you don't know anything about T since the caller is in charge of that. 实际上,实现诸如MergeFunction类的类型时,您唯一可以做的安全的事情就是返回其中一个输入,因为您对T一无所知,因为调用者对此负责。 There's certainly no way to be sure that T is an array. 当然没有办法确保T是一个数组。


Perhaps you mean for MergeFunction to be a type where the implementer chooses the generic parameter T . 也许您是说MergeFunction实现者选择通用参数T In this case, you can make the type generic instead of the function : 在这种情况下,可以使类型成为泛型而不是函数

declare type MergeFunction<T> = (def: T, file?: T, arg?: T) => T;

Note how the <T> moved from the function to the type. 注意<T>如何从函数移到类型。 The original definition is a specific type alias which refers to a generic function type , while the new definition is a generic type alias which, when you plug in a value for T , refers to a specific function type . 原始定义是指泛型函数类型特定类型别名 ,而新定义是泛型类型别名 ,当您插入T的值时, 泛型类型别名指的是特定函数类型 (Sorry if that's confusing.) It is now much easier to implement some specific type of this. (抱歉,这很令人困惑。)现在,实现这种特定类型的方法要容易得多。 For example: 例如:

const concatenateStrings: MergeFunction<string> = 
  (def: string, file?: string, arg?: string) =>
    def + (file ? file : "") + (arg ? arg: "");

The function concatenateStrings is a MergeFunction<string> . 函数concatenateStringsMergeFunction<string>

At this point it seems like it should be simple to represent arrayMerge as some kind of MergeFunction<> . 此时,将arrayMerge表示为某种MergeFunction<>似乎应该很简单。 Unfortunately it isn't. 不幸的是,事实并非如此。 TypeScript lacks the sort of generics you need here. TypeScript缺少您在此处需要的通用类型 What you want to say is something like: 想要说的是一样的东西:

const arrayMerge: <T> MergeFunction<T[]> = // invalid syntax
  (def: T[], file: T[] = [], arg: T[] = []): T[] =>
    ([] as T[]).concat(def).concat(file || []).concat(arg || []);

But you can't do that directly (as the linked issue describes). 但是您不能直接执行此操作(如链接问题所述)。 The closest you can get is to add a layer of indirection, such as a function call: 您可以获得的最接近的结果是添加一个间接层,例如函数调用:

const makeArrayMerge = <T>(): MergeFunction<T[]> =>
  (def: T[], file: T[] = [], arg: T[] = []): T[] =>
    ([] as T[]).concat(def).concat(file || []).concat(arg || []);

Now makeArrayMerge is a function that, when called with a specified type parameter T , produces a MergeFunction<T> . 现在, makeArrayMerge是一个函数,当使用指定的类型参数T调用该函数时,将生成 MergeFunction<T> This works, but is harder to use (and doesn't infer types the way you'd like): 这可行,但是更难使用(并且不会以您想要的方式推断类型):

const numArray = makeArrayMerge<number>()([0, 1, 2], [3, 4, 5]);

Oh well, that's the best I can do given the limitations of TypeScript generics. 哦,鉴于TypeScript泛型的局限性,这是我能做的最好的事情。 It's up to you to decide if you really need the above indirection or if some specific array type will work for you. 由您决定是否确实需要上述间接寻址或某些特定的数组类型是否适合您。 Hope that helps. 希望能有所帮助。 Good luck! 祝好运!

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

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