I am given a large complicated interface X that I cannot modify, I would like to define some smaller types based on the properties and sub-properties within the interface X that I want to use as types for parameters of a function. I would also like to avoid redeclaring separately what is already inside X.
interface X {
a:number;
c:{
aa:number;
cc:{
aaa:string;
}
},
d?:{
aa:number;
cc:{
aaa:string;
}
},
e:{
aa:number;
cc:{
aaa:string;
}
}[]
}
I understand that I can use mapped types to access the sub-type [Edit note: sub-type is the wrong terminology, this should be called Nested-level types, see answer below] this should be of the object, for example:
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
However, things got a bit hairy when the property is possibly undefined. If I want to get at the type at X.d.cc...(which should give {aaa:string} ) how do I do it? Or is it even possible?
The following two attempts gives an error:
type D_CC1 = X["d"]["cc"]; // error? Due to the (d?) possibly undefined?
type D_CC2 = Required<X["d"]>["cc"]; // error also?
Separately, I am also a bit confused when arrays are involved, for example above for 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 }
The third line seems to work, but I am not sure what is the logic of using [0] -- seems hacky. I would like to know if this is the right way.
Edit: Changed type names from D_CC to D_CC1 and D_CC2 to avoid ambiguity.