Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flow types with constant strings, and dependent types

Tags:

Say I have the following constant string:

export default const FOO = 'FOO'

Say I import this in a flow annotated file like so:

import FOO from '../consts/Foo'

I then have a function:

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

This doesn't typecheck with:

  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

So my questions are:

1) is it possible to use constants in flow types, how can I reproduce this behaviour?

2) Is it possible to do dependent types in flow? so for example, could I encode, through types, that the string that is returned must be the same string that is passed into the example function?

EDIT: Clarification to part 2: Is it possible to in some way indicate that the foo parameter passed into the example function is in fact the same string as the string at the foo key in the return object? Or to assert that the input and output have the same length (for say a shift cipher function). Or say contain a permutation of the same characters? (for a shuffle).

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

like image 765
Abraham P Avatar asked Feb 13 '17 01:02

Abraham P


People also ask

What is a constant string?

A String Literal, also known as a string constant or constant string, is a string of characters enclosed in double quotes, such as "To err is human - To really foul things up requires a computer." String literals are stored in C as an array of chars, terminted by a null byte.

Can you type in flow?

No Apple Pencil? No problem – Flow works with any stylus or touch input.


2 Answers

Instead of declaring FOO as a const, declare it as a disjoint union with just one branch:

type FOO = "FOO"

Then your code can be updated like this:

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

If you use any value besides the exact string literal "FOO" where a FOO is required, then it is a compile error.

If you would prefer to keep your constant, then you'll need to name the type differently, as they would collide. So you could do:

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

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

Unfortunately, I can't see a way to avoid duplicating the string literal, because type disjoint union definition syntax only permits literals and types, not variables even if they are constants.

like image 117
Peter Hall Avatar answered Oct 16 '22 13:10

Peter Hall


Found a workaround for the issue, Instead of using flow type inference we can specify the literal type

export default const FOO:'FOO' = 'FOO'

then in the function you can use as

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

Because when you declare the constant type is inferred to be string also I believe flow doesn't support setting type definitions from variables or constants.

like image 35
v3n0msnake Avatar answered Oct 16 '22 14:10

v3n0msnake