How to properly type Box
when using polymorphism via as
?
#1978
-
I have an input component that uses import React, { forwardRef } from 'react'
import { Box } from "theme-ui";
import { Align, Autocomplete } from '@/components/Input/types';
type InputType = 'text' | 'password' | 'email' | 'tel' | 'number' | 'url';
export interface IInputProps {
autoComplete?: Autocomplete;
children?: never;
id?: string;
maxLength?: number;
minLength?: number;
name?: string;
required?: boolean;
textAlign?: Align;
type?: InputType;
value?: string;
disabled?: boolean;
}
export const Input = forwardRef<HTMLInputElement, IInputProps>(
(
{
autoComplete = 'off',
disabled = false,
maxLength,
minLength,
name,
required = false,
textAlign = 'left',
type = 'text',
value,
},
ref
) => {
const intrinsicProps = { autoComplete, maxLength, minLength };
return (
<Box width='100%'>
<Box
{...intrinsicProps}
as={"input"}
sx={{ textAlign }}
type={type}
autoCapitalize='off'
autoCorrect='off'
disabled={!required && disabled}
ref={ref}
value={value}
name={name}
required={!disabled && required}
/>
</Box>
);
}
); Everything seems to be correct but I got two errors with this. First one is because I am using the
Second one is because I am specifying a
If I remove the Am I doing anything wrong? What's the best way to type this? Thank you in advance. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
Worth mentioning that I was able to get rid of the first error by specifying import React, { forwardRef, ComponentPropsWithRef, FunctionComponent } from 'react'
import { Assign, Box, BoxOwnProps } from "theme-ui";
import { Align, Autocomplete } from '@/components/Input/types';
// Custom interface for a `Box` that exports `input` via `as`
export interface BoxInputProps
extends Assign<ComponentPropsWithRef<'input'>, BoxOwnProps> {}
export interface IInputProps extends BoxInputProps {
autoComplete?: Autocomplete;
children?: never;
id?: string;
maxLength?: number;
minLength?: number;
name?: string;
required?: boolean;
textAlign?: Align;
type?: string;
value?: string;
disabled?: boolean;
}
// Arbitrary `Box` component that implements custom interface
const BoxInput: FunctionComponent<BoxInputProps> = ({ children, ...props }) => <Box as={"input"} {...props}>{children}</Box>
export const Input = forwardRef<HTMLInputElement, IInputProps>(
(
{
disabled = false,
name,
required = false,
textAlign = 'left',
type = 'text',
value,
},
ref
) => {
return (
<Box sx={{ width: '100%' }}>
<BoxInput
as={"input"}
sx={{ textAlign }}
type={type}
autoCapitalize='off'
autoCorrect='off'
disabled={!required && disabled}
ref={ref}
value={value}
name={name}
required={!disabled && required}
/>
</Box>
);
}
); This works, however I strongly believe there is a better way to do it. Any thoughts? |
Beta Was this translation helpful? Give feedback.
-
Please don't. I'd discourage from using polymorphic Radix UI has a reusable library for proper https://www.radix-ui.com/docs/primitives/utilities/polymorphic It's probably the best executed If you want to read more about it: Andrew Branch from TypeScript team has a great blogpost about polymorphic components -- https://blog.andrewbran.ch/polymorphic-react-components/ |
Beta Was this translation helpful? Give feedback.
-
I appreciate your thoughts @hasparus. So what you are saying is that |
Beta Was this translation helpful? Give feedback.
Please don't.
theme-ui
and@theme-ui/components
exportInput
component.I'd discourage from using polymorphic
as
prop in TypeScript if you care about your build times. It's a footgun. I managed to crash TypeScript compiler with it a couple times.Radix UI has a reusable library for proper
as
prop typings if you really need it.https://www.radix-ui.com/docs/primitives/utilities/polymorphic
It's probably the best executed
as
prop implementation you can get, and they still deprecated it in favor of child cloningasChild
prop.If you want to read more about it: Andrew Branch from TypeScript team has a great blogpost about polymorphic components -- https://blog.andrewbran.ch/polymorphic-react-…