Use undefined
wherever is possible. Do not use null.
Use umbrella modules (index.ts) carefully to prevent issues with cyclic imports.
When some optional values depend on a value, use invariants to make sure that contracts are not violated:
export interface IProps {
isEditable?: boolean;
onValueChange?: () => any;
}
export default class Editor extends Component<IProps> {
public render() {
const { isEditable, onValueChange } = this.props;
if (isEditable) {
invariant(
onValueChange,
"Editor is editable, but onValueChange is missing",
);
}
// Some other code
}
}
With invariants, we can follow a safer way to access data which might be undefined until the data is loaded. To prevent errors caused by undefined values, define a method to get the data and use it everywhere you need to access the data, like so:
public render() {
const { title, body } = this.getPost();
// skipped
}
// skipped
private getPost = () => {
const { postData, slug } = this.props;
// Use invariant to throw an error when the required value is undefined
invariant(postData.post, `No post for slug ${slug}`);
// Use the exclamation operator to tell TypeScript that the value is defined
return postData.post!;
};
// skipped
Correct:
{foo && <Foo>{foo}</Foo>}
Wrong:
{foo ? <Foo>{foo}</Foo> : null}