给了我一个无法修改的大型复杂接口X,我想基于接口X内的属性和子属性来定义一些较小的类型,这些类型和子属性我想用作函数参数的类型。我还想避免单独重新声明X中已经存在的内容。
interface X {
a:number;
c:{
aa:number;
cc:{
aaa:string;
}
},
d?:{
aa:number;
cc:{
aaa:string;
}
},
e:{
aa:number;
cc:{
aaa:string;
}
}[]
}
我知道我可以使用映射类型访问子类型[编辑说明:子类型是错误的术语,应称为嵌套级类型,请参见下面的答案],这应该是对象的内容,例如:
type C = X["c"]; // { aa:number; cc:{ aaa:string } }
type C_CC = X["c"]["cc"]; // { aaa: string }
type D = X["d"]; // { aa:number; cc:{ aaa:string } } | undefined
但是,当该属性可能未定义时,事情变得有些繁琐。如果我想获得X.d.cc ...(应该给出{aaa:string})的类型,我该怎么做?还是有可能?
以下两次尝试都会产生错误:
type D_CC1 = X["d"]["cc"]; // error? Due to the (d?) possibly undefined?
type D_CC2 = Required<X["d"]>["cc"]; // error also?
另外,当涉及数组时,例如在上面的E中,我也有些困惑:
type E = X["e"]; // { aa:number; cc:{ aaa:string } }[]
type E_CC1 = X["e"]["cc"]; // error
type E_CC2 = X["e"][0]["cc"]; // got the result I wanted: { aaa: string }
第三行似乎有效,但是我不确定使用[0]的逻辑是什么-似乎很hack。我想知道这是否正确。
编辑:将类型名称从D_CC更改为D_CC1和D_CC2,以避免产生歧义。
答案 0 :(得分:2)
如果查看一下界面,您会发现/std:c++latest /O2 /W3
属性实际上定义为数组。
e
这就是您需要使用索引器e:{
aa:number;
cc:{
aaa:string;
}
}[] // NOTICE THIS!
来获取该数组的项目类型的原因。这不是hack,实际上是从2.1开始添加在打字稿中的,官方名称为indexed access types, also called lookup types。
答案 1 :(得分:1)
只是一个细节,但是为了不混淆术语,界面中的内容不是子类型,而是嵌套级别的类型。嵌套类型具有顶级类型。子类型是可以在需要具有该子类型的类型的任何地方使用的类型。
接下来,您所说的映射类型实际上就是我们所说的键入运算符。这是一种在形状中查找属性类型的方法。
映射类型用于映射对象的键和值类型,看起来像这样:
type MyMappedType = {
[Key in K]: ValueType
}
这也是您可以利用keyof运算符的地方。 Key in keyof Something
例如,要使形状中的所有字段为可选(为此,有一个名为Partial<Object>
的内置映射类型),可以使用mapped types
:
type ShapeAllOptional = {
[K in keyof MyShape]?: MyShape[K]
}
现在继续您的问题。
type D_CC1 = X["d"]["cc"]; // error? Due to the (d?) possibly undefined?
您可以使用类似的东西
type myStype = NonNullable<X['d']>['cc']
关于使用
type E_CC1 = X["e"]["cc"]; // error
type E_CC2 = X["e"][0]["cc"]; // got the result I wanted: { aaa: string }
是的,它是一个数组,每个项目都具有该形状。我不知道这是不是很老套,但是我确实看到了一些看起来“干净”的东西。
type E_CC2 = X["e"][number]["cc"];
我知道没有更好的方法。
啊,我差点忘了。
type D_CC2 = Required<X["d"]>["cc"]; // error also?
请注意,此处要说的是使X ['d']中的所有属性成为必需,即aa
和cc
,它们已经是必需的。 Required<X>
我想实现您想要的目标。