2017-02-15 2 views
4

У меня есть эта ситуация и нет смысла для значимого изменения структуры данных. Поэтому я не могу добавить тег. Есть ли способ различать типы без тега? Я попробовал утаивание, но это не сработало. Смотрите мои exampleНесвязанные союзы без тегов

type Result = Done | Error; // a disjoint union type with two cases 
type Done = { count: number } 
type Error = { message: string } 

const doSomethingWithDone = (obj: Done) => {/*...*/} 
const doSomethingWithError = (obj: Error) => {/*...*/} 

const f = (result: Result) => { 
    if (result.count) { 
    doSomethingWithDone(result) 
    } else { 
    doSomethingWithError(result) 
    } 
} 

Ошибки:

5: const doSomethingWithDone = (obj: Done) => {/*...*/} 
            ^property `count`. Property not found in 
10:  doSomethingWithDone(result) 
          ^object type 
6: const doSomethingWithError = (obj: Error) => {/*...*/} 
            ^property `message`. Property not found in 
12:  doSomethingWithError(result) 
          ^object type 

ответ

0

Это имеет смысл, так как ваши типизации не говорят, что Done не может иметь свойство count.

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

By AugustinLF

+0

Такой подход не сработает, если 'count' является '0' или' 'message' является '' '. Я предполагаю, что мой ответ был занижен, потому что на первый взгляд мои типы выглядят так, как будто они меняют структуру ваших данных, о которых вы заявили, что не можете сделать. Однако добавление необязательных полей по-прежнему совместимо с данными, которые вы описали, и эта форма позволяет вам проверить на '! == undefined', который позаботится о случаях ложности. –

1

Flow не поддерживает такого рода вещи, как элегантно, как это делает непересекающиеся союзы. Однако точные типы могут помочь. Проблема в вашем примере, что я мог бы сделать

const x: Error = {message: 'foo', count: 'bar'}; 
f(x); 

присваивание допустимо, потому что мой объект буквальным удовлетворяет интерфейс x. Итак, хотя вы знаете, что если что-то есть Error, у него есть свойство message, вы ничего не знаете о других свойствах, которые у него есть. Итак, проверка наличия свойства count не доказывает, что у вас есть действительный объект типа Done.

Точные типы могут помочь здесь:

type Result = Done | Error; // a disjoint union type with two cases 
type Done = {| count: number |} 
type Error = {| message: string |} 

const doSomethingWithDone = (obj: Done) => {/*...*/} 
const doSomethingWithError = (obj: Error) => {/*...*/} 

const f = (result: Result) => { 
    if (result.count) { 
    doSomethingWithDone(result) 
    } else if (result.message) { 
    doSomethingWithError(result) 
    } 
} 

// Expected error. Since Error is an exact type, the count property is not allowed 
const x: Error = {message: 'foo', count: 'bar'}; 
f(x); 

(tryflow link)

Обратите внимание, что в дополнение к созданию типов точно, я должен был изменить ваш else к else if. И, очевидно, использование точных типов имеет недостаток, что ваш объект не может иметь посторонние поля. Но, я думаю, это лучший вариант, если вы абсолютно не можете добавить поле дискриминатора, чтобы использовать несвязанные объединения.

Смежные вопросы