【问题标题】:Union of enums is not the same as enum?枚举的联合与枚举不一样吗?
【发布时间】:2019-03-22 08:31:35
【问题描述】:

我有一些对象共享很多属性,但有一小部分是不同的。它们的区别在于它们的 ID,它是枚举中的一个值。我想将它们键入为相同泛型的子类型,以便利用类型保护来了解哪些属性是可访问的。

例子:

enum ItemIDs {
    ITEM_TYPE_1,
    ITEM_TYPE_2
}

// Generic item with shared properties
interface GenericItem<ID, Data> {
    id: ID
    data: Data
}

// Specific items where the 'data' property can be different shapes
type SpecificItemOne = GenericItem<ItemIDs.ITEM_TYPE_1, { content: string }>
type SpecificItemTwo = GenericItem<ItemIDs.ITEM_TYPE_2, { amount: number }>

// Specific item is a union of all specific items
type SpecificItem = SpecificItemOne | SpecificItemTwo;

// Take item and test that typescript can work out what properties are available
// It works!
const testTypeGuard = (item: SpecificItem) => {
    if (item.id === ItemIDs.ITEM_TYPE_1) {
        item.data.content = ''
    } else if (item.id === ItemIDs.ITEM_TYPE_2) {
        item.data.amount = 0;
    }
    return item;
}

// Try to create item where ID can be any from ID enum
const breakTypeGuard = (id: ItemIDs, data: any) => {
    // Type 'ItemIDs' is not assignable to type 'ItemIDs.ITEM_TYPE_2'.
    // WHY
    testTypeGuard({ id, data });
}

interactive on the ts site

似乎是说它不能将所有枚举值分配给特定的子类型。我不明白为什么这是一个问题,因为它与其他类型联合在一起确实接受所有枚举值。

我做错了什么?

感谢您的帮助。

【问题讨论】:

    标签: javascript typescript enums


    【解决方案1】:

    问题在于,当您发送{ id, data } 作为参数时,这被视为对象文字类型

    // This function you declared is expecting a SpecificItem type parameter
    // and you are sending an object literal type parameter
    const testTypeGuard = (item: SpecificItem) => {
        if (item.id === ItemIDs.ITEM_TYPE_1) {
            item.data.content = ''
        } else if (item.id === ItemIDs.ITEM_TYPE_2) {
            item.data.amount = 0;
        }
        return item;
    }
    

    因此,类型不匹配,这就是您收到错误的原因。 您需要做的是按照@przemyslaw-pietrzak 的建议发送指定类型的对象,如下所示:

    // Try to create item where ID can be any from ID enum
    const breakTypeGuard = (id: ItemIDs, data: any) => {
        // Type 'ItemIDs' is not assignable to type 'ItemIDs.ITEM_TYPE_2'.
        // WHY
        testTypeGuard({ id, data } as SpecificItem);
    }
    

    【讨论】:

      【解决方案2】:

      在我看来,您的代码没有任何问题。 TS 有时不会评估类型(可能是因为性能问题)。

      如果你想让这段代码正常工作,我建议添加testTypeGuard({ id, data } as SpecificItem);。这不是很不安全,因为 TS 不允许映射所有类型。例如:

      let fn = (arg: 42) => 42;
      fn(1); // Argument of type '1' is not assignable to parameter of type '42'.
      fn(1 as number) // Argument of type 'number' is not assignable to parameter of type '42'.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-12
        • 2012-09-16
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多