@modular-component/with-default-props
Version:
ModularComponent stage for handling default props. Part of the @modular-component/default package.
81 lines (72 loc) • 2.24 kB
text/typescript
import {
addTo,
wrap,
ModularContext,
GetConstraintFor,
GetValueGetterFor,
StageParams,
StageReturn,
} from '@modular-component/core/extend'
type NonNullableFields<Type> = {
[key in keyof Type]-?: undefined extends Type[key] ? never : key
}[keyof Type]
type NullableFields<Type> = {
[key in keyof Type]: undefined extends Type[key] ? key : never
}[keyof Type]
type OptionalNullable<Type> = {
[key in NonNullableFields<Type>]: Type[key]
} & {
[key in NullableFields<Type>]?: Type[key]
}
type Merge<Props, DefaultProps extends Partial<Props>> = OptionalNullable<{
[key in keyof Props | keyof DefaultProps]-?: key extends keyof Props
? key extends keyof DefaultProps
? Props[key] extends undefined | infer U
? U
: Props[key]
: Props[key]
: DefaultProps[key]
}> extends infer U
? { [key in keyof U]: U[key] }
: never
type OnlyRequiredInConstraint<Original, Constraint> = {
[key in keyof Constraint & keyof Original]: undefined extends Original[key]
? undefined extends Constraint[key]
? never
: key
: never
}[keyof Constraint & keyof Original]
type Constraint<Context extends ModularContext> = Partial<Context['props']> &
Pick<
GetConstraintFor<Context, 'props'>,
OnlyRequiredInConstraint<
Context['props'],
GetConstraintFor<Context, 'props'>
>
> extends infer U
? { [key in keyof U]: U[key] }
: never
export function defaultProps<
Context extends ModularContext,
Default extends Constraint<Context>,
>(useDefault: GetValueGetterFor<Context, 'props', Default>) {
return addTo<Context>()
.on('props')
.provide((args): Merge<Context['props'], Default> => {
const defaultProps = wrap(useDefault)(args)
const merged = {
...(args as { props: Context['props'] }).props,
}
Object.entries(defaultProps).forEach(([prop, value]) => {
if (merged[prop] === undefined) {
merged[prop] = value
}
})
return merged
})
}
export type WithDefaultProps<Context extends ModularContext> = <
Default extends Constraint<Context>,
>(
...args: StageParams<typeof defaultProps<Context, Default>>
) => StageReturn<typeof defaultProps<Context, Default>>