带有递归、条件和匹配键的TypeScript泛型

带有递归、条件和匹配键的TypeScript泛型,typescript,generics,typescript-generics,Typescript,Generics,Typescript Generics,我有以下类型和2个通用参数: type Result<INPUT, SPEC> = ... 简言之: 如果INPUT和SPEC是对象,那么Result应该是具有INPUT键的对象 对于INPUT的每个键:检查SPEC是否包含相同的键 如果true,则此键的值为Result 如果false,则此键的值为true 其他信息: 如果INPUT和SPEC是对象,则SPEC是INPUT的子集。这意味着:INPUT可以是{foo:42,bar:42},但是SPEC只允许包含foo或bar

我有以下类型和2个通用参数:

type Result<INPUT, SPEC> = ...
简言之:

  • 如果
    INPUT
    SPEC
    是对象,那么
    Result
    应该是具有
    INPUT
    键的对象
  • 对于
    INPUT
    的每个键:检查
    SPEC
    是否包含相同的键
  • 如果
    true
    ,则此键的值为
    Result
  • 如果
    false
    ,则此键的值为
    true
其他信息:

  • 如果
    INPUT
    SPEC
    是对象,则
    SPEC
    INPUT
    的子集。这意味着:
    INPUT
    可以是
    {foo:42,bar:42}
    ,但是
    SPEC
    只允许包含
    foo
    bar
    或两者都可以,或者为空

这在TypeScript中可能吗?

根据您的描述,这种类型应该可以做到:

export type Result<INPUT, SPEC> = INPUT extends object ? SPEC extends object ? {
    [K in keyof INPUT]: SPEC extends Record<K, infer SPECK> ?
        Result<INPUT[K], SPECK> :
        true
} : never : never;

// r is { foo: true; bar: never; goo: { a: never; b: true; }; }
type r = Result<{
    foo: number,
    bar: string,
    goo: { a: number; b: string }
}, { bar: number,  goo: { a: number }}>
导出类型结果=输入扩展对象?规格扩展对象?{
[K in keyof INPUT]:规格扩展记录?
结果:
真的
}:从不:从不;
//r是{foo:true;bar:never;goo:{a:never;b:true;};}
类型r=结果
您可能缺少的部分是
SPEC extends Record
,此测试类型是否使用键
K
扩展记录,并将该键的类型放入
SPECK

您没有明确说明在else分支上发生了什么(如果任何一个类型参数都不是对象,那么我将
never
放在那里,但您可以根据需要进行自定义)


如果没有100%正确,请告诉我,我们可以根据需要进行调整。

Btw。看起来TypeScript知道扩展记录的含义。您应该能够编写以下内容:
SPEC扩展记录?结果
@BenjaminM编译器不理解
记录
本身,它理解它下面的映射类型并找出键之间的关系。但你是对的,你的方式也很有效
export type Result<INPUT, SPEC> = INPUT extends object ? SPEC extends object ? {
    [K in keyof INPUT]: SPEC extends Record<K, infer SPECK> ?
        Result<INPUT[K], SPECK> :
        true
} : never : never;

// r is { foo: true; bar: never; goo: { a: never; b: true; }; }
type r = Result<{
    foo: number,
    bar: string,
    goo: { a: number; b: string }
}, { bar: number,  goo: { a: number }}>