简体   繁体   English

打字稿嵌套泛型

[英]Typescript nested generics

How do I nest the same type that uses generics?如何嵌套使用泛型的相同类型?

interface programConfig<T extends Record<string, any>> {
  // other types removed; not relevant to the question
  commands?: { [key: string]: programConfig<???> }; // how do I type this?
}

More complete ts playground example that shows what I'm trying to accomplish更完整的ts playground示例,显示了我正在尝试完成的工作

You can specify a second generic to encompass the sub elements of the programConfig, in this example I constrained the inner ones to not allow a 3rd level of nesting since supporting arbitrary nesting would be annoying and hopefully not necessary您可以指定第二个泛型来包含 programConfig 的子元素,在这个例子中,我限制内部的不允许第三级嵌套,因为支持任意嵌套会很烦人,希望没有必要

playground 操场


interface BaseProgramConfig<T extends Record<string, unknown> >{
  options?: {
    [K in keyof T]: {
      validator?: () => T[K]
    }
  },
  handler?: (data: T) => void
}
interface programConfigWithCommands<T extends Record<string, unknown>, Sub extends Record<string, Record<string, unknown>>> extends BaseProgramConfig<T> {
  commands?: {[K in keyof Sub]: BaseProgramConfig<Sub[K]>}
}

class Program<T extends Record<string, unknown>, Comms extends Record<string, Record<string, unknown>>> {
  constructor(config: programConfigWithCommands<T,Comms>) { }
}

const foo = new Program({
  options: {
    'fruit': { validator: () => 'asdf' },
    'animal': { validator: Number },
  },
  handler: ({ fruit, animal, thing }) => { // fruit and animal are properly typed based on options above
    console.log(fruit, animal)
  },
  commands: {
    foo: {
      options: {
        'tree': { validator: () => 'asdf' },
        'person': {},
      },
      handler: ({ tree, person, thing }) => { // tree is typed as string, person is typed as unknown
        console.log(tree, person)
      },
    }
  }
});

You just need to call new Program again, like here:你只需要再次调用new Program ,就像这里:

type programConfig<T extends Record<string, any> = Record<string, any>> = {
  options?: {
    [K in keyof T]: {
      validator?: () => T[K]
    }
  },
  handler?: (data: T) => void,
  commands?: { [key: string]: Program<Record<string,unknown>> }; // here use sub-programs that have nothing to do with T
}

class Program<T extends Record<string, any> = Record<string, any>> {
  constructor(config: programConfig<T>) { }
}

const foo = new Program({
  options: {
    'fruit': { validator: () => 'asdf' },
    'animal': { validator: Number },
  },
  handler: ({ fruit, animal, thing }) => { // fruit and animal are properly typed based on options above
    console.log(fruit, animal)
  },
  commands: {
    foo: new Program({
      options: {
        'tree': { validator: () => 'asdf' },
        'person': {},
      },
      handler: ({ tree, person, thing }) => { // tree and person are typed in the same way and Program of any type is accepted in commands
        console.log(tree, person)
      },
    })
  }
});

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM