Типы потоков с постоянными строками и зависимые типы

Скажем, у меня есть следующая константная строка:

export default const FOO = 'FOO'

Скажем, я импортирую это в потоковом аннотированном файле так:

import FOO from '../consts/Foo'

Тогда у меня есть функция:

const example = (foo : string) : {| type: FOO, foo: string |} => {
  return {type: FOO, foo: foo}
}

Это не typecheck с:

  6: const example = (foo : string) : {| type: FOO, foo: string |}=> {
                                                         ^^^^^^^^^^^^^^ string. Ineligible value used in/as type annotation (did you forget 'typeof'?)
  6: const example = (foo : string) : {| type: FOO, foo: string |}=> {
                                                         ^^^^^^^^^^^^^^ FOO

Итак, мои вопросы:

1) можно ли использовать константы в типах потоков, как я могу воспроизвести это поведение?

2) Можно ли делать зависимые типы в потоке? например, можно ли кодировать через типы, что возвращаемая строка должна быть той же строкой, которая передается в функцию example?

EDIT: Разъяснение к части 2: Возможно ли каким-либо образом указать, что параметр foo, переданный в функцию example, фактически является той же строкой, что и строка в foo в возвращаемом объекте? Или утверждать, что вход и выход имеют одинаковую длину (например, функцию сдвигового шифра). Или сказать, содержат перестановку одних и тех же символов? (для перетасовки).

https://en.wikipedia.org/wiki/Dependent_type

Ответ 1

Вместо объявления FOO как const объявить его как несвязное объединение только с одной ветвью:

type FOO = "FOO"

Затем ваш код может быть обновлен следующим образом:

const example = (foo : string) : {| type: FOO, foo: string |} => {
  return {type: "FOO", foo: foo}
}

Если вы используете любое значение, кроме точного строкового литерала "FOO", где требуется FOO, то это ошибка компиляции.

Если вы предпочитаете сохранять свою константу, тогда вам нужно будет указать тип по-разному, так как они будут сталкиваться. Таким образом, вы можете сделать:

const FOO = "FOO"
type FooType = "FOO";

const example = (foo : string) : {| type: FooType, foo: string |} => {
  return {type: FOO, foo: foo}
}

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