【问题标题】:Parsing string literals into enum array将字符串文字解析为枚举数组
【发布时间】:2018-04-25 16:12:23
【问题描述】:

我在 API 响应中收到以下内容:

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

其中响应​​将始终包含一组角色(USERPRESENTERORGANIZERADMIN)。

我想将其转换为有效的 TypeScript 数组 (Role[]),其中类型 Role 定义如下:

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

有什么想法吗?

【问题讨论】:

  • presenterorganizer 是从哪里出现的? ALso 预期的输出不清楚
  • 如果您正在寻找加速使用Symbols 将是一个好主意
  • 不,我只是想将收到的字符串解析为有效的枚举。
  • 您是否只想将响应类型转换为Role[]?使用as 使用通常的演员表有问题吗?例如,const roles = response.roles as Role[]?
  • 你有什么理由不能在里面放一个断言来让 TypeScript 知道类型?即as Role[]

标签: javascript json typescript json-deserialization


【解决方案1】:

您的Role 类型不是枚举。它只是一种限制为特定值的字符串类型。

您可以将结果转换为Role[],TypeScript 会很高兴。这假设传入的数据永远不会有错误的值!

const data: {roles: Role[]} = JSON.parse('{"roles": ["ADMIN", "USER"]}');
data.roles // TypeScript knows it is a Role[]

【讨论】:

  • 如果数据可能有错误的输入,只需运行 if 即可:)
  • @Victor:但是以可扩展的方式对if 进行编码很棘手。
  • @T.J.Crowder 但除了有一个模型来验证来自 API 的输入之外别无他法。另一种方法是使用JSON Schema,它将为您处理ifs
  • @Victor:不知道你所说的“没有其他方式”是什么意思给了my answer
【解决方案2】:

可以将其转换为您的联合类型:

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

但是您可能想要验证其内容,而不仅仅是信任 API。 :-) 在this question's answers 上绘图,您可以通过使用对象的键来创建类型,而不是按字面定义它(请参阅accepted answer 了解原因):

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

export type Role = keyof typeof roleStrings;

然后给自己一个验证函数:

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

然后是一个健壮的转换函数,例如:

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

(如果您不需要单独使用它们,可以将它们组合起来)

然后使用它:

// 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

【讨论】:

  • 这里是我所说的ifif (!isRole(s))
  • 我很感激,是的。这很重要!
  • 如果您不信任来自 API 的值,或者想要针对 API 合约的未来更改进行防御性编码,这绝对是更好的答案。
【解决方案3】:

如果我得到了你,那就是你想要做的。

enum RoleEnum {
  USER,
  PRESENTER,
  ORGANIZER,
  ADMIN
}

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

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

console.log(parsed)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    相关资源
    最近更新 更多