Typescript-具有通用类型函数的索引签名

时间:2020-09-05 14:07:09

标签: typescript

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

让我尝试解释一下:

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

df <- structure(list(COlA = c(1, 2), 
                     COlB = c("list(ved = \"19\", ved_name = \"No\", vedd = \"11\")",  
"list(ved = c(\"65\", \"83\", \"2\"), ved_name = c(\"At\", \"Re\", \"Rum\"), vedd = c(\"11\", \"11\", \"11\"))" )), 
                row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame" ))

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

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

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

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

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

但是,当然,如果我这样做了,我会在foosTwo.bar和foosTwo.baz上丢失任何形式的实际输入-它们都只是interface FoosTwo {[K:string]: Foo<any>} const foosTwo:FoosTwo = { bar: x => x.nest, baz: y => y.nest } 。这是有道理的-编译器将如何知道我想要什么?

但是有什么方法可以告诉编译器Foo的内联类型是什么,即类似这样的东西(我意识到这是行不通的)?

Foo<any>

换句话说,是否有某种方法可以为编译器提供足够的信息,以找出bar是interface FoosTwo {[K:string]: Foo<any>} const foosTwo:FoosTwo = { bar<number>: x => x.nest, baz<string>: y => y.nest } 而baz是Foo<number>而不需要为每个函数明确定义完整类型? / p>

非常感谢

2 个答案:

答案 0 :(得分:0)

一个选项:

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

答案 1 :(得分:0)

根据上面@ 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的解决方案同样有效,尽管其表达方式与我提出的问题略有不同。他获得了答案(也让我睁开了使用泛型的某些力量的印象)。

此处是a playground,提供了完整的解决方案。

相关问题