我可以根据它是否存在于后代中来指定递归 属性 规则吗?

Can I specify a recursive property rule based on whether or not it is present in a descendant?

我想指定一个名为 Item 的类型,它可以嵌套如下:

两者都

type Item {
    ...;
    item: Item;
    answer: {
        ...;
        //(does not contain property "item")
        }
    }

type Item {
    ...;
    //(does not contain property "item")
    answer: {
        ...;
        item: Item
        }
    }

Item 类型可以有 item:Item 作为直系子代 属性,或者作为 属性 answer 下面的孙代,但不能同时有。

上下文:我正在尝试实施 item property of the QuestionnaireResponse resource from the FHIR specification

这应该可以解决问题:

type FirstOrSecondLayer<T, I, A extends string> = XOR<T & I, T & Record<A, I>>

type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;

type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = (T | U) extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;

type Item = Expand<FirstOrSecondLayer<{
    a: string
    b: string
    answer: {
      c: string
    }
  },{
    item: Item
  }, "answer">
>

这里发生了很多事情。为了演示目的,我添加了一些额外的属性 abc。您传递类型 without item 作为 TI 是独占对象类型。对于 A,您传递嵌套 I.

的 属性 的名称

我使用了 and XOR from 中的 Expand 类型。

以下是一些测试用例:

const t1: Item = {
  a: "",
  b: "",
  item: {} as Item,
  answer: {
    c: ""
  }
} // works

const t2: Item = {
  a: "",
  b: "",
  answer: {
    c: "",
    item: {} as Item,
  }
} // works


const t3: Item = {
  a: "",
  b: "",
  item: {} as Item,
  answer: {
    c: "",
    item: {} as Item, // error
  }
} 

让我知道这是否适用于您的用例。

Playground