Flow: Declare that a value should be a literal

Created on 13 Aug 2016  路  7Comments  路  Source: facebook/flow

Currently there is now way to declare that a value should be a literal. This can be useful for declaring constraints for type parameters, e. g. type Foo<T: ('foo' | 'bar' | 'baz') & $StringLiteral> means that you can't use 'foo' | 'bar' as a parameter, you should pick exactly one.

enhancement feature request

Most helpful comment

Another use case could be something like this:

const createAction = <T: string, P>(type: T): { type: T }  => {
  return ({ type })
}

I would like to constraint T to a string literal type (not only string literal value), so I would have to call it like this:

const action = createAction(('FOO' : 'FOO'))`
(action.type: 'BAR') // Error :)

But since I can call it without the specific cast

const action = createAction('FOO')
(action.type: 'BAR') // No Error will pop up here :(

This is really useful to extract data with utility types but is really easy to forget passing the cast.

Hopefully it makes sense :)

All 7 comments

Hmm, interesting! The normal subtyping rules for unions should allow any subset of union members to be a subtype of the whole union. That is, A|B, B|C, and A|C are subtypes of A|B|C.

I can imagine that a $StringLiteral kind would be useful to describe any string with literal information, but even then I'd expect a union of string literals to be a subtype of that type. That is, "foo"|"bar" would be a subtype of $StringLiteral because each arm of the union is a subtype.

Can you share a bit more about your use case?

@samwgoldman

I was just playing with new $PropertyType at it turns that it only works if you pass a string literal directly, so there is no way to use it with generic functions.

There other option to make it work is to make $PropertyType<T, 'A' | 'B'> to be the same as $PropertyType<T, 'A'> | $PropertyType<T, 'B'>

This could further help with a more dynamic $PropertyType as I wrote in #2310

Another use case could be something like this:

const createAction = <T: string, P>(type: T): { type: T }  => {
  return ({ type })
}

I would like to constraint T to a string literal type (not only string literal value), so I would have to call it like this:

const action = createAction(('FOO' : 'FOO'))`
(action.type: 'BAR') // Error :)

But since I can call it without the specific cast

const action = createAction('FOO')
(action.type: 'BAR') // No Error will pop up here :(

This is really useful to extract data with utility types but is really easy to forget passing the cast.

Hopefully it makes sense :)

How to address it?

6115 (now closed as a duplicate) has some examples showing that Flow already treats some types as just literal values, but it doesn't let us get to it.

I second the need for this use case

@Zaggen's example allows for much more correct typing of Redux actions/payloads

Was this page helpful?
0 / 5 - 0 ratings