I have a static three static properties (Header
, Body
, and Footer
) set to a Dialog
component. However, typescript throws the following error after wrapping the Dialog
component in styled-components.
Property 'Header' does not exist on type 'StyledComponentClass...
Here is my /Dialog.tsx
:
import { Dialog as BlueprintDialog, IDialogProps } from '@blueprintjs/core';
import * as React from 'react';
import styled from 'styled-components';
import Body from './Dialog.Body';
import Footer from './Dialog.Footer';
import Header from './Dialog.Header';
/** ************************************************************************* */
type DefaultProps = {
className: string;
};
export interface DialogProps extends IDialogProps {
children?: React.ReactNode;
className?: string;
primary?: boolean;
}
class Dialog extends React.PureComponent<DialogProps> {
static displayName = 'UI.Dialog';
static defaultProps: DefaultProps = {
className: '',
};
static Body: typeof Body;
static Footer: typeof Footer;
static Header: typeof Header;
render() {
return <BlueprintDialog {...this.props} />;
}
}
/** ************************************************************************* */
export default styled(Dialog)``;
And here is my index.ts
where I piece it all together:
import Dialog from './Dialog';
import DialogBody from './Dialog.Body';
import DialogFooter from './Dialog.Footer';
import DialogHeader from './Dialog.Header';
Dialog.Body = DialogBody; // TS Compilation Error :/
Dialog.Footer = DialogFooter; // TS Compilation Error :/
Dialog.Header = DialogHeader; // TS Compilation Error :/
export default Dialog;
I've tried doing the following, which works, but now interpolation fails for the root Dialog
component:
import { Dialog as BlueprintDialog, IDialogProps } from '@blueprintjs/core';
import * as React from 'react';
import styled from 'styled-components';
import Body from './Dialog.Body';
import Footer from './Dialog.Footer';
import Header from './Dialog.Header';
/** ************************************************************************* */
type DefaultProps = {
className: string;
};
export interface DialogProps extends IDialogProps {
children?: React.ReactNode;
className?: string;
primary?: boolean;
}
class Dialog extends React.PureComponent<DialogProps> {
static displayName = 'UI.Dialog';
static defaultProps: DefaultProps = {
className: '',
};
render() {
return <BlueprintDialog {...this.props} />;
}
}
/** ************************************************************************* */
const Styled = styled(Dialog)``;
class WithSubmodules extends Styled {
static Body: typeof Body;
static Footer: typeof Footer;
static Header: typeof Header;
}
export default WithSubmodules;
An example of interpolation that throws the Cannot call a class as a function
error:
export default styled(InterpolationExample)`
${Dialog.Header} { /* WORKS :) */
border: 1px solid green;
}
${Dialog} { { /* Throws Error :/ */
border: 1px solid pink;
}
`;
So I did some tinkering and got something to work. If anybody has a better approach then please let me know!
What I ended up doing is importing the StyledComponentClass
from styled-components
, then extending it with static properties in the following way:
interface WithSubmodules extends StyledComponentClass<DialogProps, {}> {
Body: typeof Body;
Footer: typeof Footer;
Header: typeof Header;
}
Next, I cast the returned StyledComponent
to my new extended type, WithSubmodules
:
export default styled(Dialog)`` as WithSubmodules;
Here is everything together:
import { Dialog as BlueprintDialog, IDialogProps } from '@blueprintjs/core';
import * as React from 'react';
import styled, { StyledComponentClass } from 'styled-components';
import Body from './Dialog.Body';
import Footer from './Dialog.Footer';
import Header from './Dialog.Header';
/** ************************************************************************* */
type DefaultProps = {
className: string;
};
export interface DialogProps extends IDialogProps {
children?: React.ReactNode;
className?: string;
primary?: boolean;
}
class Dialog extends React.PureComponent<DialogProps> {
static displayName = 'UI.Dialog';
static defaultProps: DefaultProps = {
className: '',
};
render() {
return <BlueprintDialog {...this.props} />;
}
}
/** ************************************************************************* */
interface WithSubmodules extends StyledComponentClass<DialogProps, {}> {
Body: typeof Body;
Footer: typeof Footer;
Header: typeof Header;
}
export default styled(Dialog)`` as WithSubmodules;
Again, if anyone has a better approach then let me know!
Thanks