typescript - 使用动态字符串对允许的枚举值进行类型保护?

标签 typescript enums typeguards

我正在处理来自第 3 方的一些数据,我想通过 id 将其转换为 map ,但前提是数据有效。我有一个允许的属性的枚举,但无法弄清楚如何以编译器允许的方式检查数据是否有效。我尝试在枚举上使用带有 in 运算符的 if 语句进行检查:

/** Allowed action values */
enum Actions {
    Update = 'Update',
    Delete = 'Delete'
}

/** Validated app events */
type AppEvent = {
    id: string;
    action: Actions;
}

/** 3rd party data I want to validate */
type RawEvent = {
    id: string;
    // ❗️I want to make sure this string is an allowed enum
    action: string
}

type AppEventsById = {
    [id: string]: AppEvent
}

const possiblyInvalidEvents: RawEvent[] = [
    {
        id: 'typescript',
        action: 'Update'
    },
    {
        id: 'uh oh',
        action: 'oops'
    }
]

const eventsById: AppEventsById = {}

possiblyInvalidEvents.forEach(event => {
    // ❓Here I'm attempting to check that 3rd party action field is one of the allowed enums
    if (event.action in Actions) {
        eventsById[event.id] = {
            id: event.id,
            // 💥Type 'string' is not assignable to type 'Actions'
            action: event.action
        }
    }
})
// => I want eventsById to include the { id: 'typescript' } object, but not { id: 'uh oh' }

尝试分配给 action 会引发此错误:类型“string”无法分配给类型“Actions”。

最佳答案

你想要一个user-defined type guard函数来检查string是否是有效的Actions成员。这是一种显式告诉编译器如果结果为 true 则应使用某些 bool 值表达式来缩小值类型的方法。最简单的代码重构如下:

function isValidAction(str: string): str is Actions {
    return str in Actions;
}

possiblyInvalidEvents.forEach(event => {
    if (isValidAction(event.action)) {
        eventsById[event.id] = {
            id: event.id,
            action: event.action // no error anymore
        }
    }
})

这个 str in Actions 检查实际上依赖于枚举的键和值相同的事实,但这可能并不总是正确的。我可能会觉得检查枚举的实际值而不是键更舒服,这写起来有点令人讨厌,但至少不太可能突然中断:

function isValidAction(str: string): str is Actions {
    return (Object.keys(Actions) as Array<keyof typeof Actions>).
        some(k => Actions[k] === str);
}

但这取决于你。好的,希望有帮助;祝你好运!

Playground link to code

关于typescript - 使用动态字符串对允许的枚举值进行类型保护?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60012770/

相关文章:

Typescript 有联合,那么枚举是多余的吗?

c++ - 枚举列表到 STL 容器

typescript - 如何通过 bool 值输入保护?

python - 如何在 Python 中对对象的属性执行类型保护

javascript - 在 Hangman TypeScript 游戏结束时一次显示一个下划线

generics - TypeScript 泛型传递枚举

Angular 形式验证 : compare two fields in different form groups

C++ 独立列出所有枚举标志

typescript - 如何在 TypeScript 中映射类型并添加基于 this 的类型防护?

angular - 在Ionic2中导入trackingjs作为第三方库