4

Here's what I want to accomplish:

const names = ["foo", "bar", "baz"];
type NameType = elementof names;  // This is not valid TypeScript

The behavior would be identical to this:

type NameType = "foo" | "bar" | "baz";

A solution will need to accomplish a few things.

  • Provide an ordered enumerable sequence of strings.
  • Expose the names as an addressable union of string literal types.
  • Allow string maintenance without redundant source code edits.

Can TypeScript do this?

Note: This is not the same as Convert string[] literal to string type literal, because that question doesn't require a specifically ordered sequence of strings. Union types don't produce any way to get order information at run time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
recursive
  • 83,943
  • 34
  • 151
  • 241
  • `["foo", "bar", "baz"]` is not a type. – SLaks Jun 05 '18 at 16:23
  • Possible duplicate of [Convert string\[\] literal to string type literal](https://stackoverflow.com/questions/44686104/convert-string-literal-to-string-type-literal) – jonrsharpe Jun 05 '18 at 16:26
  • Possibly answered in [TypeScript String Union to String Array](https://stackoverflow.com/questions/44480644/typescript-string-union-to-string-array) – jcalz Jun 05 '18 at 16:30
  • 1
    @SLaks `["foo", "bar", "baz"]` is indeed a type: a [tuple](https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple) of [string literals](https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types). – jcalz Jun 05 '18 at 16:33
  • @jcalz while that version works, the tuple type seems overkill, you don't really need tuple here .. just my 2c – Titian Cernicova-Dragomir Jun 05 '18 at 16:35
  • 1
    Yeah it depends if the ordering of the elements is important to represent in the type level, which is up to @recursive to decide – jcalz Jun 05 '18 at 17:17

1 Answers1

3

You can get the type of an item using a type query:

type NameType = typeof names[number];

The problem is that the type of names is string[], so the above code just produces string.

You can infer the string literal types for the const using a helper function.

function array<T extends string>(p: T[]) : T[] {
  return p
}

const names = array(["foo", "bar", "baz"]);
type NameType = typeof names[number];   // The same as "foo" | "bar" | "baz"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • This is perfect. When did `typeof names[number]` get introduced. The operand isn't a legal expression on its own. I didn't know you could do that. – recursive Jun 05 '18 at 17:28
  • 1
    It's parsed as `(typeof names)[number]`, which is a valid type query. It isn't `typeof (names[number])`, which is indeed an error. – jcalz Jun 06 '18 at 13:36