繁体   English   中英

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

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

我已经对类似的问题做了一些探讨,但是找不到有效的解决方案。 我有一些通用函数,但是我似乎无法正确实现它们。

简而言之,我有这个:

/** 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 || [ ])

但是,出现编译器错误:

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 '{}[]'.

我实际上如何实现这种类型?

如定义的那样,类型MergeFunction的函数必须对调用者指定的任何类型T起作用。 所以arrayMerge 不是 MergeFunction ,因为它只接受数组。 这是按指定方式实现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;

实际上,实现诸如MergeFunction类的类型时,您唯一可以做的安全的事情就是返回其中一个输入,因为您对T一无所知,因为调用者对此负责。 当然没有办法确保T是一个数组。


也许您是说MergeFunction实现者选择通用参数T 在这种情况下,可以使类型成为泛型而不是函数

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

注意<T>如何从函数移到类型。 原始定义是指泛型函数类型特定类型别名 ,而新定义是泛型类型别名 ,当您插入T的值时, 泛型类型别名指的是特定函数类型 (抱歉,这很令人困惑。)现在,实现这种特定类型的方法要容易得多。 例如:

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

函数concatenateStringsMergeFunction<string>

此时,将arrayMerge表示为某种MergeFunction<>似乎应该很简单。 不幸的是,事实并非如此。 TypeScript缺少您在此处需要的通用类型 想要说的是一样的东西:

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

但是您不能直接执行此操作(如链接问题所述)。 您可以获得的最接近的结果是添加一个间接层,例如函数调用:

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

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

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

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

暂无
暂无

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

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