Проблема здесь в том, что тип MessagePayload<MESSAGES>
- это не то, что вы думаете.Интерфейсы обычно не распределяются по объединениям, поэтому он просто оценивает:
interface OopsMessagePayload {
scope: MESSAGES;
content: string | number | boolean;
}
. Это означает, что если вы проверяете свойство scope
, оно не сужает тип свойства content
.
У TypeScript есть некоторые конструкции уровня типа, которые распределяются по объединениям, поэтому должен быть способ определить
type MessagePayloadDistributive<T> = ...
, такой, что
MessagePayloadDistributive<MESSAGES>
оценивается как
MessagePayload<MESSAGES.open> |
MessagePayload<MESSAGES.closed> |
MessagePayload<MESSAGES.redo>
Я буду использовать дистрибутивные условные типы , в которых, если у вас есть тип, такой как type D<T> = T extends U ? V : W
, где проверяемый тип T
является параметром пустого типа, условная проверка будет распределенамежду профсоюзами:
type MessagePayloadDistributive<T extends MESSAGES> = T extends any
? MessagePayload<T>
: never;
type SomeMessagePayload = MessagePayloadDistributive<MESSAGES>;
Если вы проверите это, SomeMessagePayload
соответствует желаемому типу выше.И тогда следующий код будет работать так, как вы ожидаете:
function pick(payload: SomeMessagePayload): void {
switch (payload.scope) {
case MESSAGES.open:
open(payload.content); // okay
break;
case MESSAGES.close:
close(payload.content); // okay
break;
case MESSAGES.redo:
redo(payload.content); // okay
break;
}
}
Хорошо, надеюсь, это поможет.Удачи!
Ссылка на код