React + TypeScript usage of className prop
ReactjsTypescriptReactjs Problem Overview
What is the correct way to type and use the className
prop in a custom component? I used to be able to do this:
class MyComponent extends React.Component<MyProps, {}> {
...
}
and then use my component via:
<MyComponent className="my-class" />
Note that I would not define className
in MyProps
, though React was previously typed to support this usage.
Now, I am now seeing this type error:
Property 'className' does not exist on type 'IntrinsicAttributes &
IntrinsicClassAttributes<Component<{}, ComponentState>> & Readonly<{
childr...'
What is the correct way to define / type my component that will allow me to use className
when using my component?
Reactjs Solutions
Solution 1 - Reactjs
You can use the HTMLAttributes
type, for example:
class MyComponent extends React.Component<MyProps & React.HTMLAttributes<HTMLDivElement>, {}> {
render() {
return <div className={ this.props.className }>My Div</div>
}
}
That way you can pass any of the properties that a html element might need.
If you only need the className
property then you can do this:
class MyComponent extends React.Component<MyProps & { className: string }, {}> {
render() {
return <div className={ this.props.className }>My Div</div>
}
}
Or simply add it to your MyProps
type.
Solution 2 - Reactjs
For someone who are looking solution for functional components, as I was.
type Props = {
className?: string
}
const MyComponent: React.FC<Props> = (props) => (
<div className={props.className}>{props.children}</div>
)
export default MyComponent
or if you want to declare interface separately:
interface OnlyClassNameInterface extends React.FC<{className: string}> {}
const MyComponent: OnlyClassNameInterface = (props) => (
<div className={props.className}>{props.children}</div>
)
export default MyComponent
and you can move interface to another file
import React from 'react'
type MixProps<P> = P & {className?: string}
export interface OnlyClassNameInterface<P = {}> extends React.FC<MixProps<P> {}
Solution 3 - Reactjs
add a react-native-class-name.polyfill.d.ts
import 'react-native';
// polyfill className prop for react-native Components
declare module 'react-native' {
interface TextProps {
className?: string;
}
interface PressableProps {
className?: string;
}
interface TextInputProps {
className?: string;
}
interface ViewProps {
className?: string;
}
interface InputAccessoryViewProps {
className?: string;
}
interface ImagePropsBase {
className?: string;
}
interface TouchableWithoutFeedbackProps {
className?: string;
}
// others StyleProp<?> in node_modules/@types/react-native extends up show, should not define again.
}