【问题标题】:How do I pass a generic value type accessed through an index in TypeScript?如何传递通过 TypeScript 中的索引访问的通用值类型?
【发布时间】:2020-07-06 11:10:19
【问题描述】:

我正在尝试将泛型值传递给通过索引访问的类型,但我遇到了语法错误。

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

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

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

export const onCreateNode: GatsbyNode['onCreateNode']<AGenericTypeIWantToPassIn> = ...

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

【问题讨论】:

  • 我认为错误是因为您将 {} 分配给对象,而您不能在界面中执行此操作(我相信 - 如果我错了,请纠正我)
  • @MaxCarroll 我不确定我是否理解。
  • onCreateNode?&lt;TNode extends object = {} 由于默认分配 ` = {} `,这里的这一行导致错误,您应该能够删除 = {} ,这样会少一个错误。默认赋值在类中是可能的,但在 TypeScript 中不是接口或类型
  • `onCreateNode?` 定义来自一个库。另外,我不确定删除= {} 是否会有所帮助,因为= {} 的目的是使用一个空对象作为泛型的值(如果没有提供)。泛型的extends object 部分是为了确保用于泛型的值是一个对象(即您不能将字符串作为泛型的值传入)。
  • 好吧,我认为这在 TypeScript 中是不可能的,我的编译器也说,我正在文档中寻找在接口中对泛型类型进行默认赋值的证据,但没有'还没有找到任何东西,如果我找到任何东西会更新

标签: typescript


【解决方案1】:

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

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

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

export const onCreateNode: GatsbyNodeSpecific<AGenericTypeIWantToPassIn>['onCreateNode'] = null!

这肯定会奏效,但如果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;

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

export const onCreateNode2: OnCreateGatsbyNodeSpecific<AGenericTypeIWantToPassIn> = onCreateNode;

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

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

Playground link to code

【讨论】:

  • 先生,您是 TypeScript 向导。非常感谢!
猜你喜欢
  • 2019-05-18
  • 1970-01-01
  • 2019-02-13
  • 2021-01-21
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2019-03-07
  • 2015-04-26
相关资源
最近更新 更多