How to infer literal type in Flow? - flowtype

Is there a way to infer literal type with Flow in a generic way without explicit type casting?
Here's an example that should explain what I want to do. This code will not work with Flow because there's not $Literal utility type.
// explicit type casting to literal type
const a: 'flow' = 'flow
// inferring literal type
type Primitive = null | void | boolean | number | string
function literal <T: Primitive>(value: T): $Literal<T> {
return value
}
// cast type with generic function - type is inferred to 'flow' string literal
const a = literal('flow')

Related

Reflection struct field.Set with a Flag pointer value

I have a bunch of flags parsed, and I'm then trying to assign those values to fields in a struct, but I'm struggling to get a parsed flag value set into the struct because I can't type assert it or cast it.
Here is a snippet of the code I have. It's not important to worry too much about the IterFields function, basically the third argument is called for each field in the struct...
Note: there are comments in the code below which highlight the error(s).
flag.Parse()
IterFields(st, v, func(field reflect.Value, sf reflect.StructField) {
flag.VisitAll(func(f *flag.Flag) {
if f.Name == strings.ToLower(sf.Name) || f.Name == sf.Tag.Get("short") {
fmt.Printf("%+v, %T\n", f.Value, f.Value)
// PRINTS: true, *flag.boolValue
if v, ok := f.Value.(bool); ok {
fmt.Println("ok")
} else {
fmt.Println("not ok")
}
// ERROR: impossible type assertion: bool does not implement flag.Value (missing Set method)
field.Set(reflect.ValueOf(f.Value))
// PANIC: value of type *flag.boolValue is not assignable to type bool
}
})
})
f.Value is an interface type flag.Value abstracting all kinds of flag values. As your code indicates, it's not of type bool but some non-exported *flag.boolValue. You shouldn't be concerned about its dynamic type.
You may use the Value.String() method to get its value as a string, which will be either "false" or "true" for bool types, you may use simple comparison to obtain a bool from it like f.Value.String() == "true".
But a better approach would be: all flag.Value values originating from the flag package also implement flag.Getter which also has a Get() method that will directly return a bool value in case of a bool flag (wrapped in interface{} of course). Just use that:
field.Set(reflect.ValueOf(f.Value.(flag.Getter).Get()))
The above works for fields of any type (given that the flag's value type is assignable to the field's type).
For bool fields only, alternatively you may also use:
field.SetBool(f.Value.(flag.Getter).Get().(bool))

why do I need parenthesis in this dictionary initializer, in F#

with these types:
type A =
| AA
| AB
type B =
Dictionary<int, int>()
I initialize a dictionary:
Dictionary<A, B>(dict [ (A.AA, B()); (A.AB, B()) ])
but I do not understand why I need to put parenthesis after B, in the initialization code.
the following:
Dictionary<A, B>(dict [ (A.AA, B); (A.AB, B) ])
will not compile. I understand that 'B' may represent the type and 'B()' an instance of it, but I don't understand why the '()' would represent an instance?
As an additional question:
type B =
Dictionary<int, int>()
and
type B =
Dictionary<int, int>
both seem to work. Is any of the two preferred, and, if so, why?
First of all, the declaration type B = Dictionary<int, int>() does not work for me. I get an error "Unexpected symbol '(' in member definition", exactly as I would expect. Are you sure it's working for you? Which version of F# are you using?
The type Dictionary<_,_> is a class. Classes are not the same as discriminated unions (which the type A is). They are a different sort of type.
In particular, to create a value of a class type, one needs to call a constructor and pass it some parameters. This is exactly what you're doing in your very own code:
Dictionary<A, B> (dict [ (A.AA, B()); (A.AB, B()) ])
^--------------^ ^---------------------------------^
| |
constructor |
|
parameter passed to the constructor
Some classes have multiple constructors. Dictionary is one of such types.
Some constructors have no parameters, but you still have to call them. This is what you do with empty parens.
F# models parameterless .NET methods and constructors as functions that have a single parameter, and that parameter is of type unit. This is what you're doing when you say B()
B ()
^ ^^
| |
| single parameter of type unit
|
constructor
If you just say B without a parameter, then what you get is a function of type unit -> B - that is a function that expects a single parameter of type unit and when you pass it such parameter, it would return you a value of type B.

Negating types in Flow

I have a union type like this:
type ActionTypes = "ACTION_ONE" | "ACTION_TWO" | "ACTION_THREE"
And now I wonder if I can type that variable will be a string but none of the above?
for example:
const myStr: ActionTypes = "something" // no error
const myStr2: ActionTypes = "ACTION_ONE" // error
tl;dr: Maybe with type assertions, but it's hard to use effectively
I don't think there's a straightforward/possible way to exclude string literals from the string type. You might consider doing a type assertion of the variable by (ab)using $Call<F, T>, but this technique is almost certainly a bad idea:
(Try)
type ActionTypes = "ACTION_ONE" | "ACTION_TWO" | "ACTION_THREE"
type NonActionFuncType<T> =
(<T: ActionTypes>(T) => false) & (<T: string>(T) => true);
const good = "blah";
(true: $Call<NonActionFuncType<typeof good>, typeof good>) // Passes
const bad: "ACTION_ONE" = "ACTION_ONE";
(true: $Call<NonActionFuncType<typeof bad>, typeof bad>) // Fails
Pragmatically, I would suggest you look for another way to do whatever you're looking to do. Flow automatically types all string literals as string unless you specify the type, so this sort of technique won't catch too many bugs (unless you're passing variables with a literal string type, which you might be doing).

Recursive type definition in flow

I'm trying to use flow 0.53.1. Could you please help me explain this weird behavior?
This code sample:
/* #flow */
type AnySupportedType =
| AnySupportedPrimitive
| AnySupportedObject
| AnySupportedArray;
type AnySupportedArray = Array<AnySupportedType>;
type AnySupportedObject = { [string]: AnySupportedType };
type AnySupportedPrimitive = boolean | number | string | void;
type DataID = string
type Data = {
id: DataID
}
const y: Data = { id: "123" }
const x: AnySupportedType = y;
Renders this error:
17: const x: AnySupportedType = y;
^ object type. This type is incompatible with
17: const x: AnySupportedType = y;
^ union: AnySupportedPrimitive | AnySupportedObject | AnySupportedArray
Link to flow.org web-based example to play with.
Actually, this has to do with mutability. Flow cannot allow this code, since you could write x.id = 5 (after the appropriate type refinements), since the AnySupportedType type allows you to set any supported type, including a number as a property.
To solve this, you need to make the object properties covariant, effectively making them read-only:
type AnySupportedObject = { +[string]: AnySupportedType };
Note the addition of the +.
Once you do this, Flow allows the original assignment but prevents you from setting properties on x.
Check out the complete example on try.
See https://flow.org/blog/2016/10/04/Property-Variance/
The answer is that Flow has two ways to type Objects. One, your AnySupportedObject, treats the object as as dictionary where you can find an item by any key (similar to Map<string, whatever>.
The other way is as a record, where there are a specific set of known keys and each key can point to its own type of value (for example, {a: number, b: string}.
Those two types have very different meanings, though often either one can apply to a specific object. The type system keeps them distinct and forces you to treat an object in one way or the other to avoid generating type errors.

What is the syntax for defining a type when parameter has a default value?

How do I define the type of the config parameter given that it has a default value?
function (config = {}) {};
function f(config: Object = {}) {}
Or, more generally:
function f(p: T = v) {}
where T is a type, and v is a value of type T.
Interestingly, the type of function f is (p?: T): void. That is, Flow understands that providing a default value makes the parameter optional. You don't need to explicitly make the parameter type optional—although it doesn't hurt.
When writing declare function statement in a .js.flow file, you can't include the default value; it will cause an error. So you must explicitly declare that the parameter is optional:
declare function f(p?: T): void;
Flow types and default arguments in fat-arrow functions work similarly.
Given a function called foo which takes argument bar, you specify the type immediately after the argument with a colon, and then set its default value with the assignment (=) operator. Finally, immediately after closing the parentheses, you define the return value's type with another colon.
foo = (bar: string = 'baz'): string => bar;
foo(); // 'baz'

Resources