When creating an object using the following recursive type, somehow extra keys not present in the type are allowed to be added when the object is created (but not afterward). Any thoughts on why this is?
type WithChildProps<Props, ChildProps> = Props & { __childProps__: ChildProps };
type WrappedProps<Props extends Record<string, any>, WrapperPropsTuple extends any[]> = WrapperPropsTuple extends [infer ParentProps, ...infer ChildProps]
? ChildProps extends []
? WithChildProps<ParentProps, Props>
: WithChildProps<ParentProps, WrappedProps<Props, ChildProps>>
: string;
type ObjTuple = [
{ prop1: string },
{ prop2: string },
{ prop3: string },
];
type ObjProps = { mainProp: string };
type ObjWrappedProps = WrappedProps<ObjProps, ObjTuple>;
const obj: ObjWrappedProps = {
prop1: 'allowed',
__childProps__: {
prop2: 'allowed',
__childProps__: {
prop3: 'allowed',
extraProp: 'why is this allowed?', // Should error but doesn't
__childProps__: {
mainProp: 'allowed',
extraProp: 'and this also?', // Should error but doesn't
},
},
},
};
// Errors as expected
obj.extraProp = 'expected error';
obj.__childProps__.__childProps__.extraProp = 'expected error';
While I'm unable to explain this behavior, I can provide you with working utility type.
Consider this example:
type ObjTuple = [
{ prop1: string },
{ prop2: string },
{ prop3: string },
];
type ObjProps = { mainProp: string };
type Key = '__childProps__';
type Builder<
Tuple extends any[],
Level extends number[] = [],
Result = {}> =
Level['length'] extends Tuple['length']
? Result & ObjProps
: Tuple[Level['length']] & {
[Prop in Key]:
Builder<Tuple, [...Level, 1], Result>
}
// ok
const test: Builder<ObjTuple> = {
prop1: 'allowed',
__childProps__: {
prop2: 'allowed',
__childProps__: {
prop3: 'allowed',
__childProps__: {
mainProp: 'allowed',
},
},
},
};
const test2: Builder<ObjTuple> = {
prop1: 'allowed',
__childProps__: {
prop22: 'allowed', // expected error
__childProps__: {
prop3: 'allowed',
__childProps__: {
mainProp: 'allowed',
},
},
},
};
const test3: Builder<ObjTuple> = {
prop1: 'allowed',
__childProps__: {
prop2: 'allowed',
__childProps__: {
prop3: 'allowed',
__childProps__: {
mainProp2: 'allowed', // expected error
},
},
},
}
Builder
- iterates through only one property __childProps__
while Level
tuple length less than original tuple ObjTuple
. IF length is equal - return Result
merged with ObjProps
, otherwise: merge prop
from tuple by index Tuple[Level['length']]
with recursive iteration through __childProps__
.
As you might have noticed, I increase Level
tuple each time by 1
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.