首页 > 解决方案 > Typescript - 具有通用类型函数的索引签名

问题描述

是否可以在 Typescript 中定义具有索引签名的接口,其中索引引用的属性值是同一泛型类型的不同类型?

让我试着解释一下:

我有一个具有以下通用签名的函数 Foo:

interface Foo<T> {(arg1: Moo<T>): T}
interface Moo<N> {nest: N}

然后是一个对象,它将由一堆 Foo 类型的函数组成,但每个函数都有不同的泛型参数。所以:

interface Foos {
    bar: Foo<number>,
    baz: Foo<string>
}

const foos:Foos = {
    bar: x => x.nest,
    baz: y => y.nest
}

但我不想在接口中明确定义每个函数。我想要类似的东西:

interface FoosTwo {[K:string]: Foo<any>}

const foosTwo:FoosTwo = {
    bar: x => x.nest,
    baz: y => y.nest
}

但是,当然,如果我这样做,我就失去了在 foosTwo.bar 和 foosTwo.baz 上的任何类型的真正打字——它们都只是Foo<any>. 这是有道理的——编译器怎么知道我想要什么?

但是有没有办法告诉编译器 Foo 的泛型类型是什么,内联,即类似这样的东西(我意识到这不起作用)?

interface FoosTwo {[K:string]: Foo<any>}

const foosTwo:FoosTwo = {
    bar<number>: x => x.nest,
    baz<string>: y => y.nest
}

换句话说,是否有某种方法可以为编译器提供足够的信息来确定 bar 是Foo<number>和 baz 是Foo<string>什么,而无需为每个函数显式定义完整类型?

非常感激

标签: typescript

解决方案


有了上面@aleksey-l 的建议,我现在看到解决方案很简单。

将其视为索引签名的问题(这是我正在做的)是错误的。像 [K:string] 或 Record(string, any) 这样的索引签名必然是松散的,因为它们对于满足签名的任何内容都必须相同。这就是为什么我能做的最好的就是interface FoosTwo {[K:string]: Foo<any>}

事实证明,我真正想要 TS 做的是推断出一个强类型接口,就像我上面列出的手册那样:

interface Foos {
    bar: Foo<number>,
    baz: Foo<string>
}

做到这一点的方法是使用标识函数和泛型让 TS 基本上吸收一些输入信息,然后使用它来输入最终函数。所以这:

function createFoo<T>(func: Foo<T>):Foo<T> {
    return func
}

const foosTwo = {
    bar: createFoo<number>(x => x.nest),
    baz: createFoo<string>( y => y.nest)
}

一个简单的标识函数,它使用泛型提供的“提示”以我想要的方式键入返回的(相同的)函数。@alexksey-l 的解决方案同样有效,尽管它的表述与我提出的问题略有不同。他得到了答案(并且让我看到了使用仿制药的一些力量)。

这是一个提供完整解决方案的游乐场。


推荐阅读