Typescript中的类型化通用键值接口

Typescript中的类型化通用键值接口,typescript,generics,type-inference,typescript2.0,typescript-generics,Typescript,Generics,Type Inference,Typescript2.0,Typescript Generics,我有以下示例对象: let foo: Foo = { 'key1': { default: 'foo', fn: (val:string) => val }, 'key2': { default: 42, fn: (val:number) => val }, // this should throw an error, because type of default and fn don't match 'key3': { default: true, fn: (v

我有以下示例对象:

let foo: Foo = {
  'key1': { default: 'foo', fn: (val:string) => val },
  'key2': { default: 42, fn: (val:number) => val },

  // this should throw an error, because type of default and fn don't match
  'key3': { default: true, fn: (val:string) => val }
}
界面应如下所示:

interface Foo {
  [key: string]: { default: T, fn: (val:T) => any }
}
interface FooValue<T> {
  default: T;
  fn: (val: T) => any;
}

type Foo<T> = {
  [K in keyof T]: FooValue<T[K]>
}
这当然不起作用,因为没有定义
t

所以我想这样做:

interface FooValue<T> {
  default: T;
  fn: (val:T) => any;
}

interface Foo {
  [key: string]: FooValue<?>
}
接口值{
默认值:T;
fn:(val:T)=>任何;
}
接口Foo{
[键:字符串]:FooValue
}
但我也被卡住了。因为我无法定义
FooValue
的泛型类型

如果我使用
FooValue
,那么当然所有内容都被键入
any
。虽然那不起作用

我希望确保
default
的类型和
fn
的参数类型始终相同


有什么解决办法吗?或者不能这样做吗?

Foo
定义为a如何,如下所示:

interface Foo {
  [key: string]: { default: T, fn: (val:T) => any }
}
interface FooValue<T> {
  default: T;
  fn: (val: T) => any;
}

type Foo<T> = {
  [K in keyof T]: FooValue<T[K]>
}
此函数之所以有效,是因为TypeScript编译器可以执行此操作,允许它从
Foo
推断
T
。这就是它的工作原理:

let foo = asFoo({
  key1: { default: 'foo', fn: (val: string) => val },
  key2: { default: 42, fn: (val: number) => val }
});
// inferred as { key1: FooValue<string>; key2: FooValue<number>;}
希望有帮助。祝你好运


更新:上面的代码假设您可以将
foo.key1.fn('abc')
推断为类型
any
,因为
FooValue['fn']
定义为返回
any
的函数。它有点忘记了原始对象文本的输出类型。如果希望
foo
记住其属性的返回类型'
fn
方法,可以执行此稍有不同的辅助函数:

function asFoo<T, F>(foo: F & Foo<T>): F {
  return foo;
}

let foo = asFoo({
  key1: { default: 'foo', fn: (val: string) => val },
  key2: { default: 42, fn: (val: number) => val },
  // next line would cause error
  // key3: { default: true, fn: (val: string)=>val} 
})

const key1fnOut = foo.key1.fn('s') // known to be string
const key2fnOut = foo.key2.fn(123) // known to be number
函数asFoo(foo:F&foo):F{ 返回foo; } 设foo=asFoo({ 键1:{default:'foo',fn:(val:string)=>val}, 键2:{default:42,fn:(val:number)=>val}, //下一行将导致错误 //键3:{default:true,fn:(val:string)=>val} }) const key1fout=foo.key1.fn('s')//已知为字符串 const key2fnOut=foo.key2.fn(123)//已知为数字
这就行了。在这种情况下,
asFoo()
只验证输入对于某些
T
,是否为
Foo
,但它不会强制输出类型为
Foo
。根据您的用例,您可能更喜欢此解决方案而不是其他解决方案。再次祝你好运。

那么
接口Foo
呢?那么我必须在执行
时定义
T
,让Foo:Foo={…}
。然后我会为每个键设置泛型类型。这样,所有
FooValue
对象必须是相同的类型。但正如您在示例对象中所看到的:我希望每个键值都有一个不同的泛型类型。谢谢!真棒的帮助!我想辅助函数就是我所需要的。