确保枚举类型的所有值都包含在函数体中

Ensure all values of enum type are covered within function body

我的类型是:

export enum ApiFunctions {
  "setHidden" = "HIDE",
  "setReadOnly" = "SET_READ_ONLY",
  "setDescription" = "DESCRIPTION"
}
export type ValueOfApiFunction = `${ApiFunctions}`

和逻辑正在监听 window 上的事件,就像这样

window.addEventListener("message", (event) => {
                    if(event.data.type === "COMPLETE") {
                        event.data.changes.forEach((change: { fieldId: string, action: ValueOfApiFunction }) => {
                            const field = api.getFieldById(change.fieldId);

//I want to make sure that within this forEach all values of the type above are covered and if not, through a compilation error
// in this case "DESCRIPTION" isn't included so I would want a compilation error being thrown

                            if(change.action === "HIDE") {
                                field?.setVisible(false);
                            }
                            else if(change.action === "SET_READ_ONLY") {
                                field?.setName("This field is now read only")
                            }
                        })

                        resolve();
                    }
                    if(event.data.type === "MAKE_REQUEST") {
                        invoke('makeRequest', { url: event.data.url }).then(result => {
                            console.log(result);
                            iframe.contentWindow?.postMessage({
                                type: "REQUEST_COMPLETE",
                                response: result
                            }, "*")
                        });
                    }
                })

我已经在上面代码块的注释中解释了我想要实现的目标,但基本上我想确保我的类型的所有值都包含在 forEach 逻辑中,否则,编译错误。

非常感谢

您可以像这样利用 'never' 类型:

event.data.changes.forEach((change: { fieldId: string, action: ValueOfApiFunction }) => {
    const field = api.getFieldById(change.fieldId);
    if(change.action === "HIDE") {
        field?.setVisible(false);
    }
    else if(change.action === "SET_READ_ONLY") {
        field?.setName("This field is now read only")
    } else {
        const _shouldNeverBeReached: never = change.action
    }
    
})

现在,如果您忘记处理 change.action,类型将不会是 never,因此将无法编译。

更新:更明确的消息:

const exaustiveCheck = <T extends any>(t: T extends never ? never : "One of the cases was not handled") => {
  throw new Error("One of the cases was not handled")
}

然后

    } else {
        exaustiveCheck(change.action)
    }

TypeScript 没有在代码库中强制使用特定逻辑的本机功能。它主要关心的是对象没有被错误地操作,而不是检查正确的代码在做什么。不过,有一种解决方法可以让您确保针对枚举的每种可能性执行逻辑:

您可以创建一个 JSON 对象,将所有枚举值作为其键,每个键都有一个函数值,这意味着每个枚举都会执行一段逻辑,如下所示:

const fieldToAction: { [key in ValueOfApiFunction]: (field?: Field) => void } = {
  "HIDE": (field?: Field) => field?.setVisible(false),
  "SET_READ_ONLY": (field?: Field) => field?.setName("This field is now read only"),
  "DESCRIPTION": (field?: Field) => field?.setName("This field is now read only"),
}

Field 类型可能有所不同,因为示例中未提供)

您现在需要做的就是在您的 forEach 中调用它,如下所示:

fieldToAction[change.action](field);

可以找到说明此行为的游乐场 link here