skip to Main Content

I am using Typescript on my Vue page and trying to fetch user data from API.

<script setup lang="ts">
    const { data: user } = await useFetch('/api/user/info', {
        headers: useRequestHeaders(['cookie'])
    });

    if (!user.value)
        throw createError('Problems when fetching current user!');

    const myComputed = computed(() => !user.value.login); // <-- Error!
</script>

However I get tons of errors!
When I try to use user.value in script I get user.value possibly null errors and inside template I get __VLS_ctx.user possibly null errors.

Errors disappear when I remove lang="ts" attribute from script but I don’t want to do this. How to fix this problem?

My API:

export default defineEventHandler(async event => {
    const userId = await getTokenUserId(getCookie(event, 'token'));

    if (!userId)
        return setResponseStatus(event, 403);

    const db = await getDb();
    const dbUser = await db.manager.findOneBy(User, { id: userId });

    if (!dbUser)
        return setResponseStatus(event, 404);

    return {
        login:      dbUser.login,
        isEditor:   dbUser.isEditor,
        topics:     await getUserTopicsListInfo(userId),
    };
});

2

Answers


  1. Null check the value, it might solve the issue?

    <script setup lang="ts">
        const { data: user } = await useFetch('/api/user/info', {
            headers: useRequestHeaders(['cookie'])
        });
    
        if (!(user && user.value))
            throw createError('Problems when fetching current user!');
    
        const myComputed = computed(() => !(user && user.value && user.value.login)); // <-- Error!
    
    </script>
    

    You can also use the non-null assertion operator !

    <script setup lang="ts">
        const { data: user } = await useFetch('/api/user/info', {
            headers: useRequestHeaders(['cookie'])
        });
    
        if (!user!.value)
            throw createError('Problems when fetching current user!');
    
        const myComputed = computed(() => !user!.value!.login); // <-- Error!
    
    </script>
    
    Login or Signup to reply.
  2. Using a wrapped useFetch method to handle the errors uniformly instead of managing errors separately on each page could be a better practice.

    This answer will not directly answer your current question but will solve all problems that got unexpected API responses.


    define a useCustomFetch as a wrapped useFetch, which got exactly the same params and return as useFetch

    export const useCustomFetch = (
        URL,
        options = {}
    ) => {
        return useFetch(
                url,
                {
                    ...options
                }
            )
                .then(({ data, pending, error, refresh }) => {
             
                    if (error.value) {
                        
                        // you may handle the errors here uniformly
    
                        // throw error;
                    }
                    return {
                        data,
                        pending,
                        error,
                        refresh
                    };
                })
                .catch((error) => {
                    throw error;
                });
        });
    };
    

    Now, you add the code before sending and after the response. (just like the interceptors in axios)

    if (error.value) {
                        
        // you may handle the errors here uniformly
    
        const {
           statusCode,
           statusMessage,
           data
        } = error.value;
        
        // for example, you can redirect to the specific pages when got `4XX` responses (`/404`/ `/401`)
        navgiateTo(`/${statusCode}`);
    
        // also, destroy the current token if got 401
        if (statusCode === 401) {
            authStore.logout(); // here is an example
        }
    
        // or send a notification to the user
        if (process.client) {
           notify({
              type: 'error',
              title: `${statusCode} ${statusMessage}`,
              text: data?.message ?? 'Something went wrong'
           });
        }
    } 
    

    What’s more, you don’t need to add the headers: useRequestHeaders(['cookie']) each time you use useFetch, you can add it once and use it everywhere.

        ...
        
        let headers = options?.headers ?? {};
    
        headers = {
            ...useRequestHeaders(['cookie']),
            ...headers
        };
    
        options.headers = headers;
     
        useFetch(
           url,
           {
                ...options
           }
        )
    
        ...
    

    After this, you can use useCustomFetch to replace useFetch

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search