Союз перечислений не совпадает с перечислениями? - PullRequest
1 голос
/ 22 марта 2019

У меня есть несколько объектов, которые имеют много общих свойств, но имеют небольшое подмножество, которое отличается.Они различаются по их идентификатору, который является одним значением из перечисления.Я хотел бы напечатать их как подтипы одного и того же универсального, чтобы использовать защиту типов, чтобы знать, какие свойства доступны.

Пример:

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 });
}

или интерактивный насайт ts .

Кажется, он говорит, что не может присвоить все значения перечисления конкретному подтипу.Я не понимаю, почему это проблема, потому что он объединяется с другими типами, которые вместе принимают все значения перечисления.

Что я делаю не так?

Спасибо за любую помощь.

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Проблема в том, что когда вы отправляете { 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);
}
1 голос
/ 22 марта 2019

На мой взгляд, нет ничего плохого в вашем коде. 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'.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...