如何传递通过 TypeScript 中的索引访问的通用值类型?

Rob*_*per 5 typescript

我试图将通用值传递给通过索引访问的类型,但遇到语法错误。

我onCreateNode在名为 的接口上定义了一个名为 的函数类型签名GatsbyNode:

interface GatsbyNode {
  ...
  onCreateNode?<TNode extends object = {}>(
    args: CreateNodeArgs<TNode>,
    options?: PluginOptions,
    callback?: PluginCallback
  ): void
  ...
Run Code Online (Sandbox Code Playgroud)

我现在创建了一个也被命名的函数,我想在将值传递给泛型时onCreateNode为其分配类型:GatsbyNode['onCreateNode']TNode

export const onCreateNode: GatsbyNode['onCreateNode']<AGenericTypeIWantToPassIn> = ...
Run Code Online (Sandbox Code Playgroud)

但是,我在第一个尖括号 ( ) 处收到语法错误,<告诉我这不是有效的 TypeScript。

jca*_*alz 2

您正在尝试将泛型函数类型转换为引用函数的泛型类型。这是两种根本不同的泛型,尽管它们相关,但编译器并没有真正为您提供在它们之间进行转换的直接机制。请参阅此答案以获得更完整的解释;这个问题本质上是在问另一个问题在问什么。

无论如何,最直接的方法就是自己以所需的形式重写类型定义:

type GatsbyNodeSpecific<T extends object = {}> = {
  onCreateNode?(args: CreateNodeArgs<T>, options?: PluginOptions, callback?: PluginCallback): void;
}

export const onCreateNode: GatsbyNodeSpecific<AGenericTypeIWantToPassIn>['onCreateNode'] = null!
Run Code Online (Sandbox Code Playgroud)

这肯定会起作用,但如果上游定义发生变化,则可能很乏味并且可能容易出错GatsbyNode。


在另一个答案中,我展示了一种 hacky 方法来说服编译器采用泛型函数类型并将其转换为泛型类型。对于你的情况,它看起来像这样:

class GenTypeMaker<T extends object = {}> {
  getGatsbyNodeSpecific!: <A extends any[], R>(cb: (...a: A) => R) => () => (...a: A) => R;
  gatsbyNodeSpecific = this.getGatsbyNodeSpecific!(
    null! as NonNullable<GatsbyNode["onCreateNode"]>)<T>()
}
type OnCreateGatsbyNodeSpecific<T extends object> = 
  GenTypeMaker<T>['gatsbyNodeSpecific'] | undefined;
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用这个新类型:

export const onCreateNode2: OnCreateGatsbyNodeSpecific<AGenericTypeIWantToPassIn> = onCreateNode;
Run Code Online (Sandbox Code Playgroud)

这与之前的类型相同。但我怀疑任何用幻影检查上面的代码的人class都会对此感到满意,并且手动重写定义的直接冗余方法可能是更好的方法。

好的,希望有帮助;祝你好运!

Playground 代码链接