4

I have an array in a .js file and I want to use it as a tuple in a .ts file. It's a .js file because it's used by config files such as webpack.config.js. Is it possible to import it as a tuple?

E.g.:

entityTypes.js:

export default ['foo', 'bar'];

main.ts:

import type entityTypes from 'entityTypes';
typeof entityTypes[number]; // if `entityTypes` is a tuple, this would be 'foo' | 'bar'
4
  • Have you added a *.d.ts file for your entityTypes.js file? Commented Sep 18, 2020 at 8:05
  • No, I should've included in the question that the goal is to avoid duplicating the array since I don't want people to update it in only 1 place Commented Sep 18, 2020 at 8:07
  • "if entityTypes is a tuple, this would be 'foo' | 'bar'" - sounds like you want to use keyof - but I'm not sure how that would work with a [ string, string ]. Commented Sep 18, 2020 at 8:09
  • Yeah I just realized I could define entityTypes as an object and export Object.keys(entityTypes). Then, in TS, I can do keyof typeof entityTypes Commented Sep 18, 2020 at 8:11

3 Answers 3

10

In general, Typescript does not analyze JS files, and it'll just type anything imported from there as any if no other type is given. Therefore it is impossible to type the array as a tuple without retyping all the strings.

However it is possible to export it as a tuple (if the exporting code would be typescript) with as const:

export default ['foo', 'bar'] as const;

It doesn't seem to be officially documented, but this blogpost describes it in detail.

Sign up to request clarification or add additional context in comments.

1 Comment

In the .js file it'll be a warning
0

You can try something like this:

const myArray = ['foo', 'bar'] as const;

type ArrayToTuple<T extends ReadonlyArray<string>, V = string> = keyof {
    [K in (T extends ReadonlyArray<infer U> ? U : never)]: V
};

type MyTuple = ArrayToTuple<typeof myArray>;


const shouldPass: MyTuple = 'foo';
const shouldFail: MyTuple = 'hello';

Playground example

1 Comment

That converts to a union, not a tuple.
0

In my case I had an array and needed a tuple type because called code wants to make sure there is a certain number of elements in the array. My solution was this:

function To4Tuple<T>(arr: T[]): [T, T, T, T] | undefined {
  if (arr.length === 4) return [arr[0], arr[1], arr[2], arr[3]];
  else return undefined;
}

Might need more overloads for other lengths.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.