I've got a some data being fetched using RTK Query. I load this data (array of objects) in a screen and then slice some portion of it.
It's more of a typescript question but I'll post the apiSlice:
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
export const blogpostsApi = createApi({
reducerPath: 'blogpostsApi',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:3500' }),
endpoints: builder => ({
getBlogPosts: builder.query<Post[], void>({
query: () => '/todos',
transformResponse: (res: Post[], meta) => res.sort((a, b) => b.id - a.id),
}),
}),
});
The relevant excerpts from the screen:
const { data, isLoading } = useGetBlogPostsQuery();
const latestData = data?.slice(0, 10);
useEffect(() => {
if (!isLoading && latestData.length > 0 && some_other_condition) {
... some code
}
}, [latestData]);
useEffect(() => {
if (!isLoading && latestData[0].id === 'something' && some_other_condition) {
... some code
}
}, [latestData]);
As you can see, I've added the optional chaining operator to data?.slice...
(as this is a recommended solution for that on SO, from what I have seen. But then typescript also underlines all the instances of latestData.length
and latestData[0].id
.
Now I know I could silence the typescript error by adding the optional chaining operator to all those instances as well but I'm wondering it that's really the best way of doing it for 2 reasons:
- Adding it to all the instances will unnecessarily increase the compiled code length
- The way I use
latestData
above in the two effects is in conditional statements to check if it exists/is defined so it is perfectly OK for it to be undefined.
So I guess my question is what would be the correct way to solve this error. Isn't adding the optional chaining operator just a quick and dirty hack to silence the error especially if it appears in conditional statements? I know I could also suppress the error by asking Webstorm to ignore it (as per the error screenshot below)
The error:
CodePudding user response:
This is absolutely normal behaviour.
The optional chaining operator is not a Typescript thing, it's Javascript and it works like that:
myVar?.prop1?.prop2?.prop3
If myVar
is undefined
(or null
), the rest of the code won't be evaluated and the whole expression will return undefined
.
Then, if myVar
is not undefined
(or null
), then the code will try to access the prop1
property of myVar
.
Since there is a ?
after prop1
, it will repeat the same process until it finds undefined
/null
or after it reaches the end of the chain without finding any undefined
/null
.
It seems like you are confusing the Javascript ?
operator with the Typescript !
non-null assertion.
If you only want to tell the compiler that you are confident about a variable being "non-null" (that also means non undefined
), you can use the !
operator instead.
Like so:
const { data, isLoading } = useGetBlogPostsQuery();
const latestData = data!.slice(0, 10); // change this line here
useEffect(() => {
if (!isLoading && latestData.length > 0 && some_other_condition) {
... some code
}
}, [latestData]);
useEffect(() => {
if (!isLoading && latestData[0].id > 0 && some_other_condition) {
... some code
}
}, [latestData]);
However, you should really check manually if data
is not undefined
or null
before using it. And that would even release you from having to use any assertion operator !
Like that:
const { data, isLoading } = useGetBlogPostsQuery();
if (!data){
// do something to handle the problem
}
const latestData = data.slice(0, 10);
useEffect(() => {
if (!isLoading && latestData.length > 0 && some_other_condition) {
... some code
}
}, [latestData]);
useEffect(() => {
if (!isLoading && latestData[0].id > 0 && some_other_condition) {
... some code
}
}, [latestData]);