G07cha
G07cha

Reputation: 4164

Type from object's values

I've recently run into a problem of strictly specified allowed strings to be passed into a function:

type TypesList = 'foo' | 'bar' | 'baz';

function send(type: TypesList): void {};

send('foo'); // Ok
send('error'); // Error

Function listed above will only accept one of the three values of TypedList. What I'm basically trying to do is to provide type union from constant's values so in the case of future modifications I will not be required to update value everywhere.

const types = {
  foo: 'foo1',
  bar: 'bar2'
};

// Will check for "foo | bar" but I need "foo1 | bar2"
type TypesList = keyof typeof types; 

function send(type: TypesList): void {};
send(types.foo); // Invalid

I'm aware of the fact that I could just simply duplicate values from the constant or check in the function but I'm looking for a more cleaner and robust way to handle it.

Upvotes: 3

Views: 1383

Answers (1)

E_net4
E_net4

Reputation: 30062

String enums are available since TypeScript 2.4.0, which seems to be exactly what you are looking for:

enum Type {
    foo = 'foo1',
    bar = 'bar2'
}

function send(type: Type): void {};
send(Type.foo);

The enum compiles to a dictionary that maps the key name to the value, for use in run-time. If you don't need that, just make it a const enum.


Other than that, it is currently not possible to define a type as the union of all values of an object, even when that object is constant. Making a union of strings would be the usual way to go, since the main purpose of making a union of string literal types is to create an enum-like structure with string as their data type. Fortunately, we now have string enums.

As you would be using well-defined constants everywhere, there is also a chance that you do not need such a union type. In that case, you could enclose constants in a namespace and let functions take an ordinary string:

namespace Types {
    export const foo = "foo1";
    export const bar = "bar2";
}

function send(type: string): void {};
send(Types.foo);    

Upvotes: 2

Related Questions