I'm trying to create some higher-order react components that will have some default values for components "named". This is the simple implementation that I'd like to work (this is just an example to showcase the problem):
type SomeProps = {
a: string
}
type Variants = 'variantA' | 'variantB'
const somePredefinedValues: Record<Variants, SomeProps> = {
variantA: { a: 'a' },
variantB: { a: 'b' },
}
export const withVariants = <Props extends SomeProps>(Component: React.ComponentType<Props>) => {
return ({ variant, ...props }: Props & { variant?: Variants }) => {
if (!variant) {
return <Component {...props} />
}
return <Component {...somePredefinedValues[variant]} {...props} />
}
}
This obvoiuslty result with TS2322 error saying that
Type 'Omit<Props & { variant?: Variants | undefined; }, "variant">' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
Type 'Omit<Props & { variant?: Variants | undefined; }, "variant">' is not assignable to type 'Props'.
'Omit<Props & { variant?: Variants | undefined; }, "variant">' is assignable to the constraint of type 'Props', but 'Props' could be instantiated with a different subtype of constraint 'SomeProps'.
I tried many ways to get around this and fix the issue, like (a bit ugly IMO but should be correct):
type SomeProps = {
a: string
}
type Variants = 'variantA' | 'variantB'
const somePredefinedValues: Record<Variants, SomeProps> = {
variantA: { a: 'a' },
variantB: { a: 'b' },
}
export const withVariants = <Props,>(
Component: React.ComponentType<Omit<Omit<Props, keyof SomeProps>, 'variant'> & SomeProps>
) => {
return ({
variant,
...props
}: Omit<Omit<Props, keyof SomeProps>, 'variant'> & SomeProps & { variant?: Variants }) => {
const standardProps: Omit<Omit<Props, keyof SomeProps>, 'variant'> & SomeProps = props //here is the issue
if (!variant) {
return <Component {...standardProps} />
}
return <Component {...somePredefinedValues[variant]} {...standardProps} />
}
}
Which resulted in:
Type 'Omit<Omit<Omit<Props, "a">, "variant"> & SomeProps & { variant?: Variants | undefined; }, "variant">' is not assignable to type 'Omit<Omit<Props, "a">, "variant"> & SomeProps'.
Type 'Omit<Omit<Omit<Props, "a">, "variant"> & SomeProps & { variant?: Variants | undefined; }, "variant">' is not assignable to type 'Omit<Omit<Props, "a">, "variant">'.
Type 'Exclude<Exclude<keyof Props, "a">, "variant">' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'Exclude<keyof Props, "a">' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'keyof Props' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'string | number | symbol' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'string | number | symbol' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'string | number | symbol' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Type 'string' is not assignable to type '"a" | Exclude<Exclude<Exclude<keyof Props, "a">, "variant">, "variant">'.
Is there any way to achieve desired behaviour in TS?