有没有办法将类型与“关键”更改相匹配?

问题描述 投票:0回答:1

例如我写了下面的代码。

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

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

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

      },
    },
  ],
});

我想要的是这个。

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

可以吗?

addEventListener
似乎已经工作得很糟糕,所以我尝试参考这部分,但没有成功。

typescript interface type-inference
1个回答
0
投票

首先,您需要定义 event 属性的字符串

literal type
与预期
callback
参数
data
的类型之间的映射。幸运的是,TypeScript 有一种简单的方法来表示从字符串文字类型到任意类型的映射:它只是一个对象类型。就像下面的
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
表示event数组中
items
属性的
元组
。因此,如果您按照示例中所示的方式调用
func()
,那么我们希望
T
["a", "b", "c"]

当您调用

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

这是一个映射元组类型,它被包装在可变元组类型

[...
+
]
中,以向编译器提示您希望将
T
推断为元组而不是无序数组(请参阅 microsoft/TypeScript#39094,其中显示“类型
[...T]
,其中
T
是类似数组的类型参数,可以方便地用于指示对元组类型推断的偏好”)。

并且因为

{[I in keyof T]: {⋯T[I]⋯}}
同态 映射类型(请参阅“同态映射类型”是什么意思?),编译器将能够从
T
的元素推断出
items
。对于元组类型
T[I]
的数字索引
I
处的每个元素
T
items
的对应元素应该具有该类型
event
T[I]
属性,以及其
callback
data
 属性
回调参数的类型为
EventMap[T[I]]
,这意味着我们使用键 EventMap
索引到 
T[I]
。目的是编译器将从
T[I]
属性推断
event
,然后使用它来根据上下文键入
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;

看起来不错。编译器根据需要推断出

["a", "b", "c"]
T
,并且每个
data
callback
参数都根据上下文适当地键入。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.