Typescript 递归补丁类型定义

Typescript 递归补丁类型定义,typescript,recursive-type,Typescript,Recursive Type,我正在尝试编写一个泛型类型,它将一个类型作为参数(可以是普通对象、数组、基元等),并在它是普通对象或数组时重新映射值类型,以添加由配置类型描述的一些配置指令 让我们称之为假设修饰符ConfigurableT可以是任何复杂嵌套的实体Book可以是T的值,例如: 类型配置={ $test:{ 选项1:布尔型; 选项2:字符串; } }; 打印本={ id:字符串; 标题:字符串; 作者:字符串; 相关:数组; }; 类型结果=可配置; 然后,我希望Configurable正确键入检查以下表达式,其

我正在尝试编写一个泛型类型,它将一个类型作为参数(可以是普通对象、数组、基元等),并在它是普通对象或数组时重新映射值类型,以添加由
配置
类型描述的一些配置指令

让我们称之为假设修饰符
Configurable
T
可以是任何复杂嵌套的实体
Book
可以是
T
的值,例如:

类型配置={
$test:{
选项1:布尔型;
选项2:字符串;
}
};
打印本={
id:字符串;
标题:字符串;
作者:字符串;
相关:数组;
};
类型结果=可配置;
然后,我希望
Configurable
正确键入检查以下表达式,其中值可能是实际值或配置对象:

const expr1:可配置={
id:“1”,
标题:“哈利波特”,
作者:“J.K.罗琳”,
相关:[“2”、“3”]
}
常量expr2:可配置={
id:“2”,
标题:“哈利波特”,
作者:{
$test:{
选项1:正确,
选项2:“某物”
}
},
相关:[]
}
常量expr3:可配置={
id:“3”,
标题:“哈利波特”,
作者:“J.K.罗琳”,
相关:[“2”{
$test:{
选项1:正确,
选项2:“某物”
}
}]
}
常量expr4:可配置={
id:“4”,
title:true,//错误:应为字符串或配置
作者:“J.K.罗琳”,
相关:[“2”、“3”]
}
常量expr5:可配置={
id:“5”,
标题:“哈利波特”,
作者:“J.K.罗琳”,
相关的:{
$test:{
选项1:正确,
选项2:“某物”
}
}//错误:应该是(字符串|配置)的数组
}
嵌套对象或数组不应由
配置
替换,仅在需要原语值的情况下(请参见
expr5
)。 以下是我尝试过的:

类型配置={
$test:{
选项1:布尔型;
选项2:字符串;
};
};
类型可配置=记录扩展T
? {
[K in keyof T]:可配置|配置;
}
:T扩展数组
? 排列
:T;
但这会导致
expr2
expr3
失败


如果我正确理解您的需求,您可以使用
可配置
的定义:

type Configurable<T> = T extends object ?
  { [K in keyof T]: Configurable<T[K]> } :
  T | Configuration;
上面的示例编译时不会出现所需的错误。让我们检查错误:

const expr4: Configurable<Book> = {
  id: "4",
  title: true, // ERROR: should be string or Configuration
  author: "J.K. Rowling",
  related: ["2", "3"]
}

const expr5: Configurable<Book> = {
  id: "5",
  title: "Harry Potter",
  author: "J.K. Rowling",
  related: {
    $test: {
      option1: true,
      option2: "something"
    }
  } // ERROR: should be an array of (string | Configuration)
}
const expr4:可配置={
id:“4”,
title:true,//错误:应为字符串或配置
作者:“J.K.罗琳”,
相关:[“2”、“3”]
}
常量expr5:可配置={
id:“5”,
标题:“哈利波特”,
作者:“J.K.罗琳”,
相关的:{
$test:{
选项1:正确,
选项2:“某物”
}
}//错误:应该是(字符串|配置)的数组
}
你想要的错误确实产生了。看起来不错


expr2
expr2
不需要相关的
属性吗?我在这里吃疯狂的药片吗?@jcalz是的,我错了。
const expr4: Configurable<Book> = {
  id: "4",
  title: true, // ERROR: should be string or Configuration
  author: "J.K. Rowling",
  related: ["2", "3"]
}

const expr5: Configurable<Book> = {
  id: "5",
  title: "Harry Potter",
  author: "J.K. Rowling",
  related: {
    $test: {
      option1: true,
      option2: "something"
    }
  } // ERROR: should be an array of (string | Configuration)
}