Consider this scenario:
interface SomeObject {
prop1: number;
prop2: string;
prop3: {
innerProp1: number[];
innerProp2: string[];
innerProp3: {
deeperProp1: string[];
deeperprop2: boolean;
},
innerProp4: {
[key: string]: any;
},
innerProp5: {
[key: string]: any;
}
}
}
I aim to define a type that can take the shape of any object and return the same structure with specified types for the "leaf" properties. Additionally, each property should be optional. Here is an example of what I'm looking for:
type ModifyShapeType<Shape, NewType> = ???
When applied to the interface above, it should provide type safety for the identical shape but with the desired type:
const myObject: ModifyShapeType<SomeObject, boolean> = {
prop1: true;
prop2: true;
prop3: {
// innerProp1: true;
// innerProp2: false;
innerProp3: {
deeperProp1: true;
// deeperprop2: true;
},
innerProp4: true,
// innerProp5: false
}
};
I have formulated a solution, but I want to remove the original types from the structure and substitute them with the desired types while maintaining specificity on property access. This is what I have so far:
type ModifyShapeType<S, T> = Partial<Record<keyof S, Partial<S[keyof S] | T>>>;
For a live demonstration, check out the TypeScript Playground.
Current limitations include:
- The types are still inferred from the original object type, resulting in mixed types.
- All properties now share the same type (loss of specificity on read), leading to unsafe writes as well (loss of specificity on write).
Is achieving this goal feasible?