Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can you declare a type whose index signature is based on a variable?

I’m making an API call that is of the format url/ids=[id1,id2,id3] and returns an object of the form { id1: {...}, id2: {...}, id3: {...} }

I can type this as interface ApiResponse { [key: number]: ResponseShape }, but I actually have more type information than that, as that type loses the relationship between the inputted ids and the response object’s keys.

Is there a way to use the variable ids in the type? I know TS is compile time, but I was hoping I for the following scenario:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

function apiCall(ids: number[]) {
  const someRandomNumber = 10;
  fetch(url).then(
    res: ApiResponse<ids> => {
      // fine to access by the id
      const works = res[ids[0]];
      
      // undefined, because 5 isn't one of the ids we requested so won't be in the reponse type.
      cons wontWork = res[someRandomNumber]
    }
  );
}

I’m guessing this doesn’t exist since it’s pretty niche and right on the border of what should happen at compile time, but I’m hoping there’s a way to do type ApiResponse<T extends number[]> = { [id in T[number]]: ResponseShape } and pass the ids parameter in as a type

>Solution :

If you make apiCall generic and then use T[number] to get a union of all the passed IDs, you can then construct a Record where the keys are those numbers.

type ApiResponse<T extends number> = Record<T, 'foo'>;
function apiCall<T extends readonly number[]>(ids: T) {
  return fetch('url')
    .then(res => res.json()) as Promise<ApiResponse<T[number]>>;
}
apiCall([1, 2] as const)
  .then((result) => {
    console.log(result[1]); // Allowed
    console.log(result[3]); // Not allowed
  });

You’ll have to be sure to pass a tuple (like [1, 2] as const) and not a number[] for the type of the individual IDs to be preserved across the script.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading