Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ESLint `no-null` rule from `eslint-plugin-unicorn`

eslint-plugin-unicorn v19.0.0 added unicorn/no-null by default.

The reasoning behind it:
Intent to stop using null in my JS code
Some good Pros/Cons summary from that thread:
https://github.com/sindresorhus/meta/issues/7#issuecomment-568945104

Important Note

The rule only restricts using null as explicit values for variables or function arguments.
It's still valid to compare to null as in:

if (localStorage.getItem('foo') === null) {}

Other cases we'll get null from somewhere:

  • DOM API's
  • Response from the backend or external service

Personal Thoughts

While updating an existing repo to pass this rule, I realized that I can't remember an actual use case that would be greatly beneficial if I could set a value to null and later compare to it.
And if I don't compare to null anywhere, that means I could have easily not used null all along.
Also I've noticed that when we don't have null, reasoning about the code becomes a bit easier, it's one less potential value that a variable or argument can have.

How does it affects us in our day-to-day work?

React Conditional Rendering

In React components, usually we return null to tell React not to render anything (that's what the React docs show and what everyone teaches online).
But it's perfectly fine to return false, true or '' and React won't render anything as well:
https://reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored

Returning undefined doesn't work in this case, React errors about it.
So the best option is to return false.

function MyComponent() {
  if (isLoading) {
    return false;
  }

  return (
    <h1>Some content here</h1>
  );
}

React Conditional Prop

Usually we return null to tell React to do nothing on a specific event handler.
In this case, return undefined is actually preferable, as React won't even pass that prop down.
And that would be consistent with custom conditional props as well, where passing null would actually pass it down.

function MyComponent() {
  return (
    <DialogCloseButton onClick={isOkInProgress ? undefined : onClose} />
  );
}

JSON.stringify

Passing undefined to JSON.stringify 2nd argument is like not passing any value, which is the same as passing null per the MDN - JSON.stringify doc

JSON.stringify(someData, undefined, 2)

Conclusion (Dec 2020)

It feels like a lot of effort to make it work properly in a project.
Not so easy to enforce and requires some workarounds for edge cases.
I've decided not to persue this direction for now.

@FDiskas

This comment has been minimized.

Copy link

@FDiskas FDiskas commented Mar 4, 2021

That is really good explanation. Thank you.
But in typescript world is not the case:

Type 'false | Element' is not assignable to type 'ReactElement<any, any> | null'.
@alexilyaev

This comment has been minimized.

Copy link
Owner Author

@alexilyaev alexilyaev commented Mar 4, 2021

@FDiskas Well, indeed if you type your functional component with React.FunctionComponent:

const MyComponent: React.FunctionComponent<Props> = props => {}
interface FunctionComponent<P = {}> {
    (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
    propTypes?: WeakValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

Which means it expects to return a React Element object or null.
I wonder why it's not the same as the the Class Component render return value:

class Component<P, S> {
  render(): ReactNode;
}

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

But it is valid in React to return false or undefined in a Functional Component.

Also, I found that in my TypeScript projects I never actually need to type the component function itself, rather I type just the props argument.

function MyComponent(props: Props) {}

There's no big benefit in typing the function itself and it adds unnecessary noise imo.
But maybe the FunctionComponent typing is incorrect, or maybe I"m missing something :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment