I guess I'm still a C programmer at heart. I was just spinning up a very simple helper class to clean up some debug UI:
const MaybeIfValue: React.FC<{text: string, value: any}> = ({text, value}) => {
if (value === undefined) {
return null;
}
if (value === null) {
return null;
}
return (
<div>
<span>{text}</span>{value}<br/>
</div>
);
}
...and I was thinking, I really don't want any
value here. Not that it's going to matter here in practice, this is a one off helper function. But plenty of times in development over the years I've accidentally tried to render something complex. I'm still only moderately experienced with Typescript, so I don't quite know the right term for it, but what I'm wondering about, is how do I static_assert
that the compile-time typeof value is renderable? I'd call it a type trait in C . What's the term in typescript? Matching?
CodePudding user response:
I think the word you are looking for is simply "type". And avoiding the any
is a very good practice, since it drops all type checking.
ReactNode
is technically the type for something renderable, but it's a bit too permissive since it seems to allow objects and functions.
ReactChild
is the type you want, I believe. It is the type of "something renderable", that can typically just be dropped into a pair of {}
.
import React, { ReactChild } from 'react'
const MaybeIfValue: React.FC<{text: string, value: ReactChild}> = ({text, value}) => {
//...
}
Tests:
// Works
const goodStr = <MaybeIfValue text='good' value='foo' />
const goodNum = <MaybeIfValue text='good' value={123} />
const goodJsx = <MaybeIfValue text='good' value={<>Foo</>} />
// type errors
const badObj = <MaybeIfValue text='good' value={{ obj: true }} />
const badFn = <MaybeIfValue text='good' value={() => null} />
Also, quick tip, the one time you're allowed to use ==
instead of ===
is for comparisons to null
, which which be truthy for both null
and undefined
. It saves a lot of lines of code.
I, too, have a line much like this at the top of many of my own components.
if (value == null) return null
CodePudding user response:
Edit: updated example to constrain generic T
by ReactChild
after seeing this answer.
I'm not 100% sure I understand what you're asking, but it sounds like you want a strongly-typed component function.
Here's a link to the functions page in the TS handbook, specifically the section which addresses overload signatures, which is what I'm using in the snippet below to provide multiple call signatures, each with it's own return type that depends on the type of props.value
.
import {default as React, ReactChild, ReactElement} from 'react';
function MaybeIfValue (props: { text: string; value?: null | undefined }): null;
function MaybeIfValue <T extends ReactChild>(props: { text: string; value: T }): ReactElement;
function MaybeIfValue ({text, value}: { text: string; value?: unknown }) {
return (value === null || value === undefined) ? null : (
<div>
<span>{text}</span>{value}<br/>
</div>
);
};
MaybeIfValue({text: 'hello'}) // null
MaybeIfValue({text: 'hello', value: null}) // null
MaybeIfValue({text: 'hello', value: undefined}) // null
MaybeIfValue({text: 'hello', value: false}) /*
^^^^^
Error: Type 'boolean' is not assignable to type 'ReactChild'.(2769) */
MaybeIfValue({text: 'hello', value: 12}) // ReactElement
MaybeIfValue({text: 'hello', value: 'hello'}) // ReactElement
// etc...