How to set the type in Typescript when the structure is dynamic (not known)?

159 views Asked by At

I'm building a React App where I wanna fetch countries from the https://restcountries.com/v2/ API. I created a Country interface that holds the needed properties. When the fetch is finalized, I desire to validate the structure of the fetched countries, so I can initialize the properties for my Country instances. I created a validation function for this reason, and the parameter is the countries array (the result of the API call). The problem is that the structure of the countries is not known, since it comes from an external source. Of course, I can see the structure of the returned response but it can change in the future therefore I don't want to build a type based on the current structure of the API response. I know that the result should be an Array, but I don't know the structure of the country objects from the array therefore I cant create a type. Should the parameter be an Array? How should I define the type better than 'unkown'? Should it be Array instead? Please see validation function below:

const validateCountries = (APIResultCountries: any) => {
  const countries: Country[] = APIResultCountries.map((APIcountry: any) => {
    const {
      name,
      population,
      region,
      capital,
      flags,
      alpha2Code,
    }: {
      name: string;
      population: number;
      region: string;
      capital: string;
      flags: {
        svg: string;
        png: string;
      };
      alpha2Code: string;
    } = APIcountry;

    const country: Country = {
      name,
      population: population ?? UNKNOWN,
      region: region || UNKNOWN,
      capital: capital || UNKNOWN,
      //TODO: return template img src instead of UNKNOWN string for the flag
      flag: flags.svg || flags.png || UNKNOWN,
      code: alpha2Code,
    };

    return country;
  });
  return countries;
};
1

There are 1 answers

2
gerrod On BEST ANSWER

It's a versioned API, so if the format of the response changes they would also change the version (e.g. you're hitting API v2, but they're now up to v3.1). So, you can safely assume the shape of the response objects is fixed.

Based on the example response for a v2 API call, you can create a country interface that contains whatever properties you actually care about:

interface CountryResponse {
    name: string;
    capital: string;
    population: number;
    // etc
}

Make sure you're only asking for the fields you care about too - that will cut down on the response size.

Now if you really want to validate them still, you can safely assume that the incoming type corresponds to CountryResponse -

const validateCountries = (response: CountryRespose[]): Country[] => {
    // ...
}

The only caveat here is that the API doesn't state which fields might come back as null or undefined, but if it was me, I'd assume that they'll all be there until the API gives me a response that proves otherwise.