1

I'm receiving the following in an API response:

{ "roles": [ "ADMIN", "USER" ] }

where the response will always contain an array of roles (USER, PRESENTER, ORGANIZER, and ADMIN).

I want to convert it into a valid TypeScript array (Role[]), where the type Role is defined as follows:

export type Role = 'USER' | 'PRESENTER' | 'ORGANIZER' | 'ADMIN'

Any ideas?

Sammy
  • 3,395
  • 7
  • 49
  • 95

3 Answers3

3

Your Role type is not an enum. It is just a string type limited to certain values.

You can just cast the result as a Role[] and TypeScript will be happy. This assumes the incoming data never has a bad value!

const data: {roles: Role[]} = JSON.parse('{"roles": ["ADMIN", "USER"]}');
data.roles // TypeScript knows it is a Role[]
Brandon
  • 38,310
  • 8
  • 82
  • 87
  • And if data might have bad input, just run an `if` and you're done :) – Victor Apr 25 '18 at 16:30
  • 1
    @Victor: But coding that `if` in an extensible way is tricky. – T.J. Crowder Apr 25 '18 at 16:37
  • @T.J.Crowder but there's no other way than having a model to validate inputs from an API. Another way is using a [JSON Schema](http://json-schema.org/) which will handle the `if`s for you – Victor Apr 25 '18 at 16:39
  • @Victor: Not sure what you mean by "no other way" given [my answer](https://stackoverflow.com/a/50027123/157247). – T.J. Crowder Apr 25 '18 at 16:42
1

You can just cast it to your union type:

const apiRoleArray = ["ADMIN", "USER"];
const realRoleArray: Role[] = <Role[]>apiRoleArray;

BUT you probably want to validate its contents rather than just trusting the API. :-) Drawing on this question's answers, you can create the type by using the keys of an object rather than defining it literally (see the accepted answer there for why):

const roleStrings = {
    USER: "",
    PRESENTER: "",
    ORGANIZER: "",
    ADMIN: ""
};

export type Role = keyof typeof roleStrings;

then give yourself a validation function:

const isRole = (s: string): s is Role => {
    return roleStrings.hasOwnProperty(s);
};

then a robust conversion function, for example:

const rawToRoleArray = (rawArray: string[]): Role[] => {
    return rawArray.map(s => {
        if (!isRole(s)) {
            throw new Error("Invalid Role: " + s);
        }
        return <Role>s;
    });
};

(you could combine those if you don't need them separately)

then use it:

// Valid
const realRoleArray: Role[] = rawToRoleArray(["ADMIN", "USER"]); 
console.log(realRoleArray);
// Invalid
const realRoleArray2: Role[] = rawToRoleArray(["ADMIN", "FOO"]); 
console.log(realRoleArray2);

Live in the playground | Live on jsFiddle

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

If I got you corectly thats what you want to do.

enum RoleEnum {
  USER,
  PRESENTER,
  ORGANIZER,
  ADMIN
}

const parseEnum = (name: String): RoleEnum  => RoleEnum[`${name}`]

const parsed: RoleEnum[] = [ 'ADMIN', 'USER' ].map(parseEnum)

console.log(parsed)
Maciej Kozieja
  • 1,812
  • 1
  • 13
  • 32