How can I correctly use TypeScript fetch when casting the response to a custom type?

How can I correctly use fetch in TypeScript when casting the response to a custom type?

I am using window.fetch in TypeScript, but I’m encountering issues when trying to cast the response directly to my custom type. For example:

import { Actor } from './models/actor';

fetch(`http://swapi.co/api/people/1/`)
    .then(res => res.json())
    .then(res => {
        // This is not allowed
        // let a: Actor = <Actor>res;

        // I use an intermediate variable to work around this
        let a: any = res; 
        let b: Actor = <Actor>a;
    })

What is the correct method to handle the fetch response and cast it to a custom type in TypeScript? I am looking for a proper approach to using typescript fetch and type casting.

You can use type assertions after parsing the JSON response. This is a straightforward approach where you assert the type of the result once the data is available.

import { Actor } from './models/actor';

fetch(`http://swapi.co/api/people/1/`)
    .then(res => res.json())
    .then((res: any) => {
        // Type assertion after parsing JSON
        let actor: Actor = res as Actor;
        console.log(actor);
    });

In this approach, you first parse the response as any, then assert the correct type (Actor).

You can create a function that handles the fetching and casting to the custom type. This function abstracts the type casting logic.

import { Actor } from './models/actor';

async function fetchActor(url: string): Promise<Actor> {
    const response = await fetch(url);
    const data = await response.json();
    return data as Actor;
}

fetchActor(`http://swapi.co/api/people/1/`)
    .then(actor => {
        console.log(actor);
    });

In this approach, the fetchActor function handles the fetch operation and returns a promise of the Actor type.

This approach is useful when your object has a specific type but you need to add additional properties dynamically.

For example:

let user: User = new User();
(user as any).otherProperty = 'hello';
// The user object retains its original type and now has the additional property.

This technique allows you to extend an object with extra properties without losing its specific type, which can be helpful when integrating with other sources or libraries.