One simplest option will be setting a default value for your optional props. As an example, if className is optional you can change your ComponentB.js to something like this.
const ComponentB = ({ children, className="", equalWidth }) => {
return (...)
}
Also if you deconstruct your props in the function body instead of the signature TS will not complain about typings.
const ComponentB = (props) => {
const { children, className, equalWidth } = props;
return (...)
}
Answer from Tharaka Wijebandara on Stack OverflowOne simplest option will be setting a default value for your optional props. As an example, if className is optional you can change your ComponentB.js to something like this.
const ComponentB = ({ children, className="", equalWidth }) => {
return (...)
}
Also if you deconstruct your props in the function body instead of the signature TS will not complain about typings.
const ComponentB = (props) => {
const { children, className, equalWidth } = props;
return (...)
}
Assuming that ComponentB.js is going to end up as a TypeScript component:
interface ComponentBProps {
children?: ReactNode;
className?: string;
equalWidth?: boolean;
}
const ComponentB = ({ children, className, equalWidth }: ComponentBProps) => {
//
};
In the special case where all properties are optional, you could remove the ? from each property on the interface and use Partial<ComponentBProps>, but I guess that at least something will end up being a required prop.
If you want to keep ComponentB.js as it is, then an alternative solution is to create a type definitions file:
import { ReactNode, StatelessComponent } from "react";
interface ComponentBProps {
children?: ReactNode
className?: string;
equalWidth?: boolean;
}
export const ComponentB: StatelessComponent<ComponentBProps>;
If you put in this the same directory as the JavaScript file and name is ComponentB.d.ts, then you should be able to import ComponentB in your TypeScript file.
The way I have written the definition assumes that the component is a named export, not the default, i.e. it is exported like export const ComponentB in the .js file.
(probably) working example: https://github.com/fenech/tsx-jsx
Here's a similar question with an answer: React with TypeScript - define defaultProps in stateless function
import React, { Component } from 'react';
import { Text } from 'react-native';
interface TestProps {
title?: string,
name?: string
}
const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}
const Test: React.SFC<TestProps> = (props) => (
<Text>
{props.title} {props.name}
</Text>
);
Test.defaultProps = defaultProps;
export default Test;
I've found the easiest method is to use optional arguments. Note that defaultProps will eventually be deprecated on functional components.
Example:
interface TestProps {
title?: string;
name?: string;
}
const Test = ({title = 'Mr', name = 'McGee'}: TestProps) => {
return (
<p>
{title} {name}
</p>
);
}
reactjs - Selectively rendering optional component properties in React JSX - Stack Overflow
How to pass optional elements to a component as a prop in reactjs
reactjs - Default property value in React component using TypeScript - Stack Overflow
React-Typescript complaining about optional props missing (defined with prop-types)
Videos
You don't need to do anything special. Just pass the title component as a prop, and then use {this.props.title} wherever you want it to be rendered:
class Panel extends React.Component {
render() {
return <div>
{this.props.title}
<div>Some other stuff...</div>
</div>;
}
}
class App extends React.Component {
render() {
var title = <Title>My Title</Title>;
return <Panel title={title}/>;
}
}
If you don't pass any value for the title prop (or if the value is false, null, or undefined) then nothing will be rendered there.
This is a fairly common pattern in React.
you can do something like this
render(){
<div>
{this.props.title ? this.props.title : null}
{this.props.children}
</div>
}
basically if you pass a title element as a prop then create it as an element and render it. else just put in null...
to create it you would do something like this.
<Panel title={<Title>Something Here</Title>}
<div> something here</div>
</Panel>
This is generally how react should handle optional child components
Default props with class component
Using static defaultProps is correct. You should also be using interfaces, not classes, for the props and state.
Update 2018/12/1: TypeScript has improved the type-checking related to defaultProps over time. Read on for latest and greatest usage down to older usages and issues.
For TypeScript 3.0 and up
TypeScript specifically added support for defaultProps to make type-checking work how you'd expect. Example:
interface PageProps {
foo: string;
bar: string;
}
export class PageComponent extends React.Component<PageProps, {}> {
public static defaultProps = {
foo: "default"
};
public render(): JSX.Element {
return (
<span>Hello, { this.props.foo.toUpperCase() }</span>
);
}
}
Which can be rendered and compile without passing a foo attribute:
<PageComponent bar={ "hello" } />
Note that:
foois not marked optional (iefoo?: string) even though it's not required as a JSX attribute. Marking as optional would mean that it could beundefined, but in fact it never will beundefinedbecausedefaultPropsprovides a default value. Think of it similar to how you can mark a function parameter optional, or with a default value, but not both, yet both mean the call doesn't need to specify a value. TypeScript 3.0+ treatsdefaultPropsin a similar way, which is really cool for React users!- The
defaultPropshas no explicit type annotation. Its type is inferred and used by the compiler to determine which JSX attributes are required. You could usedefaultProps: Pick<PageProps, "foo">to ensuredefaultPropsmatches a sub-set ofPageProps. More on this caveat is explained here. - This requires
@types/reactversion16.4.11to work properly.
For TypeScript 2.1 until 3.0
Before TypeScript 3.0 implemented compiler support for defaultProps you could still make use of it, and it worked 100% with React at runtime, but since TypeScript only considered props when checking for JSX attributes you'd have to mark props that have defaults as optional with ?. Example:
interface PageProps {
foo?: string;
bar: number;
}
export class PageComponent extends React.Component<PageProps, {}> {
public static defaultProps: Partial<PageProps> = {
foo: "default"
};
public render(): JSX.Element {
return (
<span>Hello, world</span>
);
}
}
Note that:
- It's a good idea to annotate
defaultPropswithPartial<>so that it type-checks against your props, but you don't have to supply every required property with a default value, which makes no sense since required properties should never need a default. - When using
strictNullChecksthe value ofthis.props.foowill bepossibly undefinedand require a non-null assertion (iethis.props.foo!) or type-guard (ieif (this.props.foo) ...) to removeundefined. This is annoying since the default prop value means it actually will never be undefined, but TS didn't understand this flow. That's one of the main reasons TS 3.0 added explicit support fordefaultProps.
Before TypeScript 2.1
This works the same but you don't have Partial types, so just omit Partial<> and either supply default values for all required props (even though those defaults will never be used) or omit the explicit type annotation completely.
Default props with Functional Components
You can use defaultProps on function components as well, but you have to type your function to the FunctionComponent (StatelessComponent in @types/react before version 16.7.2) interface so that TypeScript knows about defaultProps on the function:
interface PageProps {
foo?: string;
bar: number;
}
const PageComponent: FunctionComponent<PageProps> = (props) => {
return (
<span>Hello, {props.foo}, {props.bar}</span>
);
};
PageComponent.defaultProps = {
foo: "default"
};
Note that you don't have to use Partial<PageProps> anywhere because FunctionComponent.defaultProps is already specified as a partial in TS 2.1+.
Another nice alternative (this is what I use) is to destructure your props parameters and assign default values directly:
const PageComponent: FunctionComponent<PageProps> = ({foo = "default", bar}) => {
return (
<span>Hello, {foo}, {bar}</span>
);
};
Then you don't need the defaultProps at all! Be aware that if you do provide defaultProps on a function component it will take precedence over default parameter values, because React will always explicitly pass the defaultProps values (so the parameters are never undefined, thus the default parameter is never used.) So you'd use one or the other, not both.
With Typescript 2.1+, use Partial < T > instead of making your interface properties optional.
export interface Props {
obj: Model,
a: boolean
b: boolean
}
public static defaultProps: Partial<Props> = {
a: true
};
Hi, I'm converting a React JS codebase to TS.
I just converted a component (`TabButton) that uses an Icon component that is not converted yet but uses prop-types. The problem is that TS (in TabButton) is complaining that Icon misses some props but they should be completely optional as in Icon I didn't require them.
The error text is: Type '{ component: ReactNode; }' is missing the following properties from type '{ [x: string]: any; component: any; color: any; hoverColor: any; className: any; onClick: any; }': color, hoverColor, className, onClick ts(2739)
What can I do? Thanks
TabButton.tsx Hovering over Icon in TabButton.tsx Icon.js