typescript Map函数类型

jjhzyzn0  于 2023-01-31  发布在  TypeScript
关注(0)|答案(2)|浏览(172)

我试图基于预先存在的实用程序类型构造一个函数类型,并简单地定义一个键到类型的Map:

type TypeMap = {
    a: A;
    b: B;
}

我尝试构建的类型是一个多签名函数类型,在第一个参数中使用key作为文本字符串:

type Result = {
    (key: "a"): A;
    (key: "b"): B;
}

这在TypeScript中是可能的吗?我知道函数类型并不总是很好地与Map类型放在一起。
我可以这样做,但我希望避免重复完整的密钥列表:

type TempFunc<K extends keyof TypeMap> = {
    (key: K): TypeMap[K];
};

type Result = TempFunc<"a"> & TempFunc<"b">;

注意:这是我试图完成的一个非常简化的版本;我实际的TypeMap有超过100个键。

d7v8vwbk

d7v8vwbk1#

TypeScript将具有多个调用签名的函数(也称为重载函数)视为等效于这些调用签名的交集。即:

type Result = {
    (key: "a"): A;
    (key: "b"): B;
};

行为与相同

type Result = { (key: "a"): A; } & { (key: "b"): B; };

这和

type Result = ((key: "a") => A) & ((key: "b") => B);

您可以通过使用这些Result定义中的任意一个测试以下代码来验证:

declare const r: Result;
const a = r("a");
// const a: A
const b = r("b");
// const b: B

所以如果我们可以通过编程来生成一个交集,它就相当于你所要求的。
幸运的是,我们可以通过一种条件类型推理技术来实现,这种技术涉及到类型参数在 * contravariant * 位置上(参见Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript),这类似于Transform union type to intersection type的答案:

type Result = {
  [K in keyof TypeMap]: (x: (key: K) => TypeMap[K]) => void
}[keyof TypeMap] extends (x: infer I) => void ? I : never;

// type Result = ((key: "a") => A) & ((key: "b") => B)

除了它是一个 * 分布式对象类型 *,如在ms/TS#47109中所创造的,其中我们在TypeMap的键上执行map,并立即执行index intokeyof typeMap的Map类型,以获得一个并集(由于前面提到的逆变性,它成为一个交集)。
但是你可能不需要多个调用签名,这取决于用例,因为每个调用签名都以相同的方式将输入Map到输出,通过indexing intoTypeMap的一个键,你可以得到一个非常相似的函数类型,只有一个generic调用签名:

type Result = <K extends keyof TypeMap>(key: K) => TypeMap[K];

这比上面的分配反变对象要简单得多,而且它的行为非常相似:

declare const r: Result;
const a = r("a");
// const a: A
const b = r("b");
// const b: B

也许您的用例实际上 * 需要 * 多个不同的调用签名,但如果不是这样,我肯定会推荐在这里使用泛型。
Playground代码链接

mnemlml8

mnemlml82#

试试这个:

type Result = { [K in keyof TypeMap]: (key: K) => TypeMap[K] }[keyof TypeMap];

相关问题