Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to define type for tuple: Target requires 2 element(s) but source may have fewer

I'm trying to populate an array consisting of tuples

const countries = ['sg', 'my', 'th'];
const platforms = ['ios', 'android'];

const combinationsToQuery = platforms.flatMap((platform) =>
    countries.map((cid) => [platform, cid])
); // [["ios", "sg"], ["ios", "my"], ["ios", "th"], ["android", "sg"], ["android", "my"], ["android", "th"]]

Now I'm trying to add some types to them and below is my attempt

type country = 'sg' | 'my' | 'th' | 'uk' | 'us'
type platform = 'ios' | 'android'

const countries: country[] = ['sg', 'my'];
const platforms: platform[] = ['ios', 'android'];

const combinationsToQuery: [platform, country][] = platforms.flatMap((platform) =>
    countries.map((cid: country) => [platform, cid])
);

Type '(country | platform)[][]' is not assignable to type '[platform, country][]'. Type '(country | platform)[]' is not assignable to type '[platform, country]'. Target requires 2 element(s) but source may have fewer.(2322)

If I don't specifically define [platform, country][], TS will infer combinationsToQuery to be (country | platform)[][], which doesn't sounds right either?

TS Playground

like image 450
Isaac Avatar asked Jan 21 '26 20:01

Isaac


1 Answers

The problem becomes more obvious if you look at the return type for the .map callback. If you tweak your original code to:

countries.map((cid: country) => {
  const result = [platform, cid];
  return result;
})

Above, result is typed as (country | platform)[] - not as a tuple containing two elements, but as an array whose (any number of) elements are either platform or country. (So, the resulting type of the whole combinationsToQuery isn't right either.)

You can either assert the type returned by the callback is a tuple:

const combinationsToQuery: [platform, country][]  = platforms.flatMap((platform) =>
    countries.map((cid) => [platform, cid] as [platform, country])
);

Or declare your arrays as const and the return value from the callback as const and let TypeScript infer the rest for you.

const countries = ['sg', 'my'] as const;
const platforms = ['ios', 'android'] as const;

const combinationsToQuery = platforms.flatMap((platform) =>
    countries.map((cid) => [platform, cid] as const)
);
like image 194
CertainPerformance Avatar answered Jan 23 '26 08:01

CertainPerformance