-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Question] How to properly define namespaced react components? #165
Comments
seems fine. i rarely use forwardRef :) |
Unfortunately we have to use lots of forwardRefs since its for a component library. Reason this came up is because this sort of type declaration doesnt work well with Thanks for your help! |
cc @ferdaber this seems in your wheelhouse |
It's a little bit annoying but what you can do is use import ChildComponent from './ChildComponent';
interface IProps extends React.HTMLAttributes<HTMLDivElement> {
someProp?: any;
}
const _MyComponent = React.forwardRef(
({someProp, ...otherProps}: IProps, ref: React.Ref<HTMLDivElement>) => {
return <div {...otherProps} ref={ref} />;
}
)
_MyComponent.displayName = 'MyComponent'
type TMyComponent = React.ForwardRefExoticComponent<IProps> & {
ChildComponent: typeof ChildComponent;
};
// this will have type TMyComponent, or more specifically
// `typeof _MyComponent & { ChildComponent: typeof ChildComponent }`
const MyComponent = Object.assign(_MyComponent, { ChildComponent })
export default MyComponent; |
@ferdaber thanks for the feedback! I'll give this a try and see how it looks. |
You can also create a helper function to do all of this: import ChildComponent from './ChildComponent'
function createNamespacedComponent<T extends React.JSXElementConstructor<any>, U>(getComponent: () => T, namespaceMembers: U): T & U {
const NamespaceComponent = getComponent();
return Object.assign(NamespaceComponent, namespaceMembers);
}
const MyComponent = createNamespaceComponent(
() => {
const MyComponent = React.forwardRef(
({someProp, ...otherProps}: IProps, ref: React.Ref<HTMLDivElement>) => {
return <div {...otherProps} ref={ref} />;
}
)
MyComponent.displayName = 'MyComponent'
return MyComponent
},
{ ChildComponent }
) |
Using object.assign turned out working well. It also looks pretty clean and the TS inference seems to work better than my previous implementation. Here is the general idea of what it looks like now //...
const Input = React.forwardRef<HTMLInputElement, IProps>((props, ref) => (
<input {...props} ref={ref} />
));
export default Object.assign(Input, {
Group,
GroupInsetItem,
GroupItem,
GroupText
}); |
damn that looks pretty sweet! can you PR this in somewhere that fits pls @bryceosterhaus |
#166, let me know if you need me to add anything else. |
resolved! this went great i think! |
Say I wanted to type this, I'm trying the following with no luck: export type NamespacedComponent = React.FC<any> & {
[name: string]: React.FC<any>;
};
const namespaced: NamespacedComponent = Object.assign(ButtonGroup, {
Item
}); It won't compile saying
What am I missing |
|
I typically use namespacing in my react components to group similar components. I was wondering what the best approach to defining a type here would be. I generally do something like the example below, however using
as ...
isn't ideal for me. Any other ideas how to properly type a react component that also has namespaced components?The text was updated successfully, but these errors were encountered: