You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用// @ts-check时Object.freeze枚举引发类型校验问题求助

解决TS-check下Object.freeze枚举的类型不匹配问题

问题根源

你遇到的报错是因为TypeScript的字面量类型推断:当执行let popupImageAnimationState = PopupImageAnimationState.HIDDEN;时,TS会把变量类型精准锁定为"hidden"(而非所有枚举值的联合类型)。但PopupImageAnimationState.FADE_OUT的类型是"fadeOut",两个字面量类型完全无重叠,TS会判定这种比较无意义,从而抛出错误。

去掉Object.freeze后,TS会把枚举对象的属性类型推断为宽泛的string,变量类型也同步变为string,比较自然不会报错,但枚举对象会失去只读特性,不符合需求。

解决方案

以下是几种在纯JS中保留Object.freeze只读特性,同时解决类型报错的方法:

方案1:用JSDoc定义联合类型并标注变量

通过@typedef定义所有枚举值的联合类型,再给变量标注该类型,让TS明确变量可以是枚举中的任意值:

// @ts-check 

/**
 * @typedef { "hidden" | "visible" | "fadeIn" | "fadeOut" | "recenter" | "slideOutToLeft" | "slideOutToRight" | "slideInFromLeft" | "slideInFromRight" } PopupImageAnimationStateType
 */

/** @type {Readonly<Record<string, PopupImageAnimationStateType>>} */
const PopupImageAnimationState = Object.freeze({
    HIDDEN              : "hidden",
    VISIBLE             : "visible",
    FADE_IN             : "fadeIn",
    FADE_OUT            : "fadeOut",
    RECENTER            : "recenter",
    SLIDE_OUT_TO_LEFT   : "slideOutToLeft",
    SLIDE_OUT_TO_RIGHT  : "slideOutToRight",
    SLIDE_IN_FROM_LEFT  : "slideInFromLeft",
    SLIDE_IN_FROM_RIGHT : "slideInFromRight"
});

/** @type {PopupImageAnimationStateType} */
let popupImageAnimationState = PopupImageAnimationState.HIDDEN;

// 无报错
if(popupImageAnimationState !== PopupImageAnimationState.FADE_OUT)
{
    console.log("not equal");
}

switch(popupImageAnimationState)
{
    case PopupImageAnimationState.FADE_IN:
    case PopupImageAnimationState.RECENTER:
    case PopupImageAnimationState.SLIDE_IN_FROM_LEFT:
    case PopupImageAnimationState.SLIDE_IN_FROM_RIGHT:
        console.log("some of them");
        break;

    default:
        console.log("the rest");
        break;
}

方案2:用JSDoc的@enum标签(更简洁)

用@enum标记枚举对象,再通过类型推导自动获取联合类型,无需手动枚举所有字符串值:

// @ts-check 

/**
 * @enum {string}
 */
const PopupImageAnimationState = Object.freeze({
    HIDDEN              : "hidden",
    VISIBLE             : "visible",
    FADE_IN             : "fadeIn",
    FADE_OUT            : "fadeOut",
    RECENTER            : "recenter",
    SLIDE_OUT_TO_LEFT   : "slideOutToLeft",
    SLIDE_OUT_TO_RIGHT  : "slideOutToRight",
    SLIDE_IN_FROM_LEFT  : "slideInFromLeft",
    SLIDE_IN_FROM_RIGHT : "slideInFromRight"
});

/** @type {typeof PopupImageAnimationState[keyof typeof PopupImageAnimationState]} */
let popupImageAnimationState = PopupImageAnimationState.HIDDEN;

// 无报错
if(popupImageAnimationState !== PopupImageAnimationState.FADE_OUT)
{
    console.log("not equal");
}

switch(popupImageAnimationState)
{
    case PopupImageAnimationState.FADE_IN:
    case PopupImageAnimationState.RECENTER:
    case PopupImageAnimationState.SLIDE_IN_FROM_LEFT:
    case PopupImageAnimationState.SLIDE_IN_FROM_RIGHT:
        console.log("some of them");
        break;

    default:
        console.log("the rest");
        break;
}

方案3:类型断言快速解决(适合简单场景)

直接用类型断言给变量指定联合类型,省去额外的类型定义:

// @ts-check 

const PopupImageAnimationState = Object.freeze({
    HIDDEN              : "hidden",
    VISIBLE             : "visible",
    FADE_IN             : "fadeIn",
    FADE_OUT            : "fadeOut",
    RECENTER            : "recenter",
    SLIDE_OUT_TO_LEFT   : "slideOutToLeft",
    SLIDE_OUT_TO_RIGHT  : "slideOutToRight",
    SLIDE_IN_FROM_LEFT  : "slideInFromLeft",
    SLIDE_IN_FROM_RIGHT : "slideInFromRight"
});

// 用类型断言指定变量为枚举值的联合类型
let popupImageAnimationState = /** @type {typeof PopupImageAnimationState[keyof typeof PopupImageAnimationState]} */ (PopupImageAnimationState.HIDDEN);

// 无报错
if(popupImageAnimationState !== PopupImageAnimationState.FADE_OUT)
{
    console.log("not equal");
}

switch(popupImageAnimationState)
{
    case PopupImageAnimationState.FADE_IN:
    case PopupImageAnimationState.RECENTER:
    case PopupImageAnimationState.SLIDE_IN_FROM_LEFT:
    case PopupImageAnimationState.SLIDE_IN_FROM_RIGHT:
        console.log("some of them");
        break;

    default:
        console.log("the rest");
        break;
}

内容的提问来源于stack exchange,提问作者Mike McCollister

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 04:37:12