Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript:深嵌套对象路径的设置值类型_Typescript - Fatal编程技术网

Typescript:深嵌套对象路径的设置值类型

Typescript:深嵌套对象路径的设置值类型,typescript,Typescript,我想找到一种方法,为嵌套对象路径的所有键提供所有值类型 我在一定程度上取得了成功,但未能为数组对象中的深层嵌套属性设置值类型 interface BoatDetails { boats: { boat1: string; boat2: number; }; ships: Array<Ship> } interface Ship { shipName: string } const boatDetails: BoatDetails = { boa

我想找到一种方法,为嵌套对象路径的所有键提供所有
值类型

我在一定程度上取得了成功,但未能为数组对象中的深层嵌套属性设置值类型

interface BoatDetails {
  boats: {
    boat1: string;
    boat2: number;
  };
  ships: Array<Ship>
}
interface Ship {
    shipName: string
}
const boatDetails: BoatDetails = {
  boats: {
    boat1: "lady blue",
    boat2: 1,
  },
  ships: [
      {shipName: "lacrose"}
  ]
};
接口船详细信息{
船只:{
boat1:字符串;
船2:编号;
};
舰船:阵列
}
接口船{
船名:string
}
const boatDetails:boatDetails={
船只:{
船1:“蓝色女士”,
船2:1,
},
船舶:[
{船名:“拉克罗斯”}
]
};
对于上面的代码,我能够成功地为嵌套对象路径设置值类型,如
boat1
值类型为string
boat2
值类型为number
ships
值类型为Array

但是无法为嵌套路径
ships.0.shipName
设置
值类型

我已从下面的链接中获取设置深嵌套对象路径类型的参考:

下面是我在typescript中设置深嵌套对象路径的值类型的尝试:

请注意:在
路径
路径值
中进行的操作对编译器来说是一种负担(您很容易得到显式递归限制警告,或者更糟糕的是,编译时间呈指数级增长),并且存在各种边缘情况


一种边缘情况是,使用模板文本轻松完成的从<代码>数字到<代码>字符串的转换不容易将<代码>字符串<代码>文本转换为等效的<代码>数字<代码>文本(有关更多信息,请参阅并回答),以及
`形式的所谓模式模板文本(如中实现的)${number}.shipName`
当前不能直接用作对象类型的键(请参阅)

因此,我们为您提供了一个索引类型,如
“0”
,您希望将其用作数组类型的键,但除非该数组类型恰好是,否则编译器将不允许您这样做:

type Oops = (string[])["0"] // error!
// ------------------> ~~~
// Property '0' does not exist on type 'string[]'

type Okay = (string[])[0] // okay
// type Okay = string
由于
“0”
不被视为数组的键,
“ships.0.shipName”
路径值
类型函数计算
“0”扩展了Ship[]
时失败,您很难过。而且没有正式的方法将
“0”
转换为
0
,或者让编译器看到
“0”
作为
keyof Ship[]
,没有标准的解决方案


所以你有点被各种各样的解决方法所困扰。一种可能是忽略元组的可能性(除了那些讨厌的东西外,元组大多已经有显式的数字字符串索引),而只是做一个
T[K]的解决方法
检查
T
是否有
number
索引签名,并且
K
可分配给
`${number}`
,如果是,则返回
T[number]

type Idx<T, K> = K extends keyof T ? T[K] :
    number extends keyof T ? K extends `${number}` ? T[number] : never : never;
类型Idx=K扩展了T?T[K]的范围:
数字扩展键T?K扩展`${number}`?T[number]:从不:从不;
现在起作用的是:

type TryThis = Idx<string[], "0">
// type TryThis = string

type StillWorks = Idx<string[], 0>
// type StillWorks = string
类型TryThis=Idx
//类型TryThis=string
StillWorks类型=Idx
//类型StillWorks=string

如果我们在您的
PathValue
类型中使用它,如下所示:

type PathValue<T, P extends Paths<T, 4>> = P extends `${infer Key}.${infer Rest}`
  ? Rest extends Paths<Idx<T, Key>, 4>
  ? PathValue<Idx<T, Key>, Rest>
  : never
  : Idx<T, P>
type PathValue=P扩展了`${infer Key}.${infer Rest}`
?Rest扩展路径
?路径值
:从不
:Idx
然后事情开始运作:

setValue(
  boatDetails,
  `ships.0.shipName`,
  "titanic"
); // okay
/* function setValue<BoatDetails, "ships.0.shipName">(
     obj: BoatDetails, path: "ships.0.shipName", value: string
): BoatDetails */
setValue(
船的细节,
`ships.0.shipName`,
“泰坦尼克号”
)好的
/*函数设置值(
对象:BoatDetails,路径:“ships.0.shipName”,值:string
):船只详情*/

还有其他可能的解决方法,可以从更任意的
T
K
对中挑出更精确的结果,但我认为这就足够了


这是否回答了您的问题?抱歉,它没有回答,但感谢您对此进行研究。我相信问题在于
0
索引没有强制显示在
数组中
类型。如果您将
ships
的类型切换为
[Ship]
您的代码可以工作。请注意
setValue()中的
V
type参数
函数实际上并没有什么作用;您可能应该删除它,并直接用
PathValue
替换对
V
的所有引用。感谢您给出如此令人惊讶的答案。您对typescript编译器工作原理的了解对typescript社区有很大帮助。