使用TypeScript将箭头函数分配给通用函数类型 [英] Assigning arrow function to generic function type with TypeScript

查看:108
本文介绍了使用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.

简而言之,我有这个:

/** 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?

推荐答案

如您所定义,类型MergeFunction的函数必须适用于 any 类型T,而 caller 指定.因此arrayMerge不是 一个MergeFunction,因为它仅接受数组.这是按指定方式实现MergeFunction的一种方法:

As you've defined it, a function of type MergeFunction must work for any type T that the caller specifies. So arrayMerge is not a MergeFunction, since it only accepts arrays. Here's one way to implement your MergeFunction as specified:

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;

实际上,实现MergeFunction之类的类型时,您唯一可以做的安全的事情就是返回其中一个输入,因为

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. There's certainly no way to be sure that T is an array.

也许您是说MergeFunction是一种类型,其中实现程序选择通用参数T.在这种情况下,您可以使 type 通用而不是 function :

Perhaps you mean for MergeFunction to be a type where the implementer chooses the generic parameter 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;

请注意<T>如何从函数移至类型.原始定义是特定类型别名,它引用泛型函数类型,而新定义是泛型类型别名,当您插入T的值,表示特定功能类型. (抱歉,这很令人困惑.)现在,实现 some 特定于此的类型要容易得多.例如:

Note how the <T> moved from the function to the type. 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. (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: "");

函数concatenateStringsMergeFunction<string>.

在这一点上,将arrayMerge表示为某种MergeFunction<>似乎应该很简单.不幸的是,事实并非如此. TypeScript缺少您需要的泛型.您想要说的是这样的:

At this point it seems like it should be simple to represent arrayMerge as some kind of MergeFunction<>. Unfortunately it isn't. TypeScript lacks the sort of generics you need here. 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 || []);

现在makeArrayMerge是一个函数,当使用指定的类型参数T进行调用时,会产生一个MergeFunction<T>.这可以工作,但是更难使用(并且不会以您想要的方式推断类型):

Now makeArrayMerge is a function that, when called with a specified type parameter T, produces a 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]);

哦,鉴于TypeScript泛型的局限性,这是我能做的最好的事情.由您决定是否确实需要上述间接寻址,或者某些特定的数组类型是否适合您.希望能有所帮助.祝你好运!

Oh well, that's the best I can do given the limitations of TypeScript generics. 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!

这篇关于使用TypeScript将箭头函数分配给通用函数类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆