例如,我编写了以下代码.

func({
  items: [
    {
      event: 'a',
      callback: (data) => {

      },
    },
    {
      event: 'b',
      callback: (data) => {

      },
    },
    {
      event: 'c',
      callback: (data) => {

      },
    },
  ],
});

我想要的是这个.

  • 当事件为‘a’时,回调因子的数据类型被推断到A接口.
  • 当事件为‘b’时,将回调因子的数据类型推断到B接口.
  • 当事件为‘c’时,回调因子的数据类型被推断到C接口.

有可能吗?

addEventListener似乎已经起作用了,所以我试着参考了这一部分,但没有奏效.

推荐答案

首先,您需要定义event属性的字符串literal type和预期的callback参数data的类型之间的映射.幸运的是,TypeScrip有一种简单的方法来表示从字符串文字类型到任意类型的映射:它只是一个object type.如下interface条所示:

interface EventMap {
    a: A;
    b: B;
    c: C;
}

我们有一个,我们可以将func()定义为generic函数,如下所示:

declare function func<T extends (keyof EventMap)[]>(arg: {
    items: [...{ [I in keyof T]: {
        event: T[I],
        callback: (data: EventMap[T[I]]) => void
    } }]
}): void;

这里,类型参数T表示items数组中event个属性中的tuple个.因此,如果您按照示例中所示的方式调用func(),那么我们希望T等于["a", "b", "c"].

当您调用func()时,编译器会查看参数的items属性,并try 将其与类型[...{[I in keyof T]: {event: T[I], callback: (data: EventMap[T[I]]) => void }]匹配.

这是一个mapped tuple type,它被包装在variadic tuple type [...+]中,以给编译器一个提示,您希望将T推断为元组,而不是无序数组(请参见microsoft/TypeScript#39094,其中它说"类型[...T],其中T是类似数组的类型参数,可以方便地用于指示推断元组类型的首选项").

由于{[I in keyof T]: {⋯T[I]⋯}}homomorphic映射类型(参见What does "homomorphic mapped type" mean?),编译器将能够从items的元素推断T.对于元组类型T的数字索引I处的每个元素T[I],items的对应元素应该具有该类型T[I]event属性以及其data回调参数是EventMap[T[I]]类型的callback属性,这意味着具有键T[I]的WE index into EventMap.其目的是编译器将从event属性推断T[I],然后使用它来contextually type callback参数data.

让我们来测试一下:

func({
    items: [
        {
            event: 'a',
            callback: (data) => {
                //     ^?(parameter) data: A
            },
        },
        {
            event: 'b',
            callback: (data) => {
                //     ^?(parameter) data: B
            },
        },
        {
            event: 'c',
            callback: (data) => {
                //     ^?(parameter) data: C
            },
        },
    ],
});
// function func<["a", "b", "c"]>(⋯): void;

看上go 不错.编译器根据需要为T推断出["a", "b", "c"],并且每个callbackdata参数被适当地上下文类型化.

Playground link to code

Typescript相关问答推荐

调用另一个函数的函数的Typescript类型,参数相同

创建一个通用上下文,允许正确推断其中的子项

在Angular中,如何在文件上传后清除文件上传文本框

在TypeScrip中分配回调时,参数的分配方向与回调本身相反.为什么会这样呢?

material 表不渲染任何数据

当方法参数和返回类型不相互扩展时如何从类型脚本中的子类推断类型

向NextAuth会话添加除名称、图像和ID之外的更多详细信息

在包含泛型的类型脚本中引用递归类型A<;-&B

我可以以这样一种方式键入对象,只允许它的键作为它的值吗?

TS如何不立即将表达式转换为完全不可变?

常量类型参数回退类型

如何将TS泛型用于react-hook-form接口?

类型';字符串|数字';不可分配给类型';未定义';.类型';字符串';不可分配给类型';未定义';

错误:NG02200:找不到类型为';对象';的其他支持对象';[对象对象]';.例如数组

在Reaction中折叠手风琴

为什么受歧视的unions 在一种情况下运作良好,但在另一种非常类似的情况下却不起作用?

组件使用forwardRef类型脚本时传递props

如何为字符串模板文字创建类型保护

如何在没有空接口的情况下实现求和类型功能?

在 TypeScript 中实现类型级别深度优先搜索