【问题标题】:How to create type safe "Recursive" type?如何创建类型安全的“递归”类型?
【发布时间】:2020-11-29 06:45:54
【问题描述】:

我想创建类型树结构,传递根节点和子节点模式。根据模式,我希望必需的属性是必需的,而不是可选的,因为它必须如此。但是我的类型测试没有通过。这是我的一段代码:

type TypedTree<TRootSchema, TChildSchema = TRootSchema> =
  {
    [K in keyof TRootSchema]: TRootSchema[K]
  } | {
    [key: string]: TypedTree<TChildSchema>
  }

const $typeTest = <T>(v: T) => v

// @ts-expect-error Required properies must be present
$typeTest<TypedTree<{ a: number }>>({ })
// ???? It fails

【问题讨论】:

  • { [K in keyof TRootSchema]: TRootSchema[K] } 不是和TRootSchema 一样吗?
  • 是的,无论如何,问题仍然存在

标签: javascript typescript testing


【解决方案1】:

我刚刚提出了可行的解决方案,需要显式传递可能的子节点键,然后类型才能工作。但是我不想这样做,我希望打字稿自己推断子键,或者其他任何东西,以便有问题的代码能够正常工作。

这是当前代码:


type Schema = Record<PropertyKey, unknown>

type SchemaTuple = [Schema, Schema]

type TypedTree2<
  TSchema extends Schema | SchemaTuple,
  TNodeKeys extends string = never,
  _TInferredRootSchema_ extends Schema = TSchema extends SchemaTuple ? TSchema[0] : TSchema,
  _TInferredChildSchema_ extends Schema = TSchema extends SchemaTuple ? TSchema[1] : TSchema
> = {
  [K in keyof _TInferredRootSchema_]: _TInferredRootSchema_[K]
} & {
  [K in TNodeKeys]?: TypedTree2<_TInferredChildSchema_, TNodeKeys>
}

$typeTest<TypedTree2<[{ a: number }, { a?: number }], 'foo' | 'bar' | 'baz'>>({
  a: 1,
  foo: {
    bar: {
      baz: {
        foo: {
          a: 10
        }
      }
    }
  }
})

// @ts-expect-error Required properties must be present
$typeTest<TypedTree2<{ a: number }>>({ })

$typeTest<TypedTree2<{ a: number }>>({ a: 1 })

$typeTest<TypedTree2<{ a: number }, 'a_2' | 'a_3'>>({
  a: 1,
  a_2: {
    a: 2,
    a_3: {
      a: 3
    }
  }
})

$typeTest<TypedTree2<{ a: number }, 'a_2' | 'a_3'>>({
  a: 2,
  // @ts-expect-error Child node keys must satisfy second type parameter
  unknown_key: { a: 3}
})

【讨论】:

    猜你喜欢
    • 2022-01-21
    • 2017-08-19
    • 2013-09-26
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    相关资源
    最近更新 更多