0

I am pretty new to typescript and am not sure how to best go about this rather common scenario. I fetch data and pass it into a template component as such:

const ProfilePage: FC = (): JSX.Element => {
  const { data, isDataLoading } = useProfileData();

  return (
    <ProfileTemplate
      data={!isDataLoading && data}
    />
  );
};

This is the ProfileTemplate component

import { profile_data, Maybe } from '../api-client';

type ProfileProps = {
  data: Maybe<profile_data>;
}

export const ProfileTemplate: FC<ProfileProps> = ({ data }): JSX.Element => {
  ...
  <StaticField label="First Name" text={data.first_name} />
  <StaticField label="Last Name" text={data.last_name} />
  ...
}

Calling it as such results in Type 'false | Maybe<profile>' is not assignable to type 'Maybe<profile>'. I can remove the conditional which checks isDataLoading first, however I then get object is possibly null errors in my <StaticField> components.

first_name and last_name can be null or empty in the database. Although I realize that's not what's causing the object is possibly null errors, rather an empty profile_data object, when no data has been returned from the server yet.

How should I best handle this situation?

My `<StaticField>` component looks like so: interface Props {
  label: string;
  text?: Maybe<string>;
}

export const StaticField: FunctionComponent<Props> = ({ label, text }): JSX.Element => {
  return (
    <Box>
      <Text color="gray.BlackCoral" className={classes.label}>
        {label}
      </Text>
      <Text>{text}</Text>
    </Box>
  );
};
1
  • What is in your useProfileData? Commented Sep 1, 2021 at 4:11

3 Answers 3

1

You should handle like this to make sure ProfileTemplate always has data

{
  !isDataLoading && <ProfileTemplate data={data} />;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot! This is less than ideal because the function needs to return something. But thanks for sharing.
1

This line here is the problem

  data={!isDataLoading && data}

I suggest you refactor your code to have conditional render like so

if (isDataLoading || !data) {
    return null
}
return (
    <ProfileTemplate data={data}/>
);

However you can simply replace the data prop with a ternary It is always good practice to extract into constants

const data = isDataLoading ? data : undefined;
return (
    <ProfileTemplate data={data}/>
);

The second option still does not account for what should be rendered when you have data undefined So you would need a render of null inside ProfileTemplate

1 Comment

Thanks a lot! Definitely what I was looking for.
0

If I understand it correctly, Maybe seems to have been defined like type Maybe<T> = T | null.

So, since you expect data to be either present or null, you can change your consumption logic to

<ProfileTemplate
  data={isDataLoading ? null : data}
/>

This will get rid of the error 'false | Maybe<profile>' is not assignable to type 'Maybe<profile>'.. This error shows up because in your existing code !isDataLoading && data can either evaluate to false or whatever the type of data is.

Secondly, since data can be null, using it to access data.first_name can be a problem. That's what TypeScript is trying to tell you. One way to "fix" it would be to use the optional chaining data?.first_name to tell the compiler that you'll access first_name iff data is defined.

1 Comment

Awesome, thank you. I added optional chaining... And then in my <StaticField> component, should I have text typed as Maybe<string>? It errors out with just string, but is there any reason to not use Maybe in that case?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.