Last active
October 25, 2017 18:38
-
-
Save asolove/550cca11eed1719e8ac6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// If I have a variant with two arms | |
type Foo = { type: "bar", bar: string } | { type: "baz", baz: string }; | |
// It would be nice if a function could handle those two arms. | |
function fromThingy(foo: Foo): string { | |
switch(foo.type) { | |
case "bar": | |
return foo.bar; | |
case "baz": | |
return foo.baz; | |
} | |
} | |
// So that, if I ever add a third arm to that variant, this function will fail to typecheck until I think about how I should handle that variant. | |
// But right now, Flow seems to demand I add a default case. | |
// It errors with: "Return undefined. This type is incompatible with string" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// After asking the flowtype freenode channel, @marudor came up with an asesome workaround: | |
type Foo = { type: "bar", bar: string } | { type: "baz", baz: string }; | |
function fromThingy(foo: Foo): string { | |
switch(foo.type) { | |
case "bar": | |
return foo.bar; | |
case "baz": | |
return foo.baz; | |
default: | |
return foo; | |
} | |
} | |
// Leaving out the default, the function doesn't typecheck. (Logically it should, but Flow doesn't know this.) | |
// Adding in a default, means the function will continue to type-check even if new variants are added. This takes away the whole point of having the compiler check that we've handled all the variants. | |
// | |
// If we want the function to pass type checking now, but fail to type-check when new variants are added, | |
// we can use this magic incantation `default: return foo` where foo must be the variable whose variant types | |
// are being matched on. | |
// | |
// At first I thought this was a quite silly hack and you ought to be able to return any type from the default case. After all, | |
// `foo` is a `Foo`, and this function has to return a `string`, so obviously Flow is just ignoring the type of the thing | |
// in the default case. But this is not true. Returning any value other than `foo` (or a string, obviously) fails. | |
// | |
// @marudor's suggested explanation is this: In each switch case, Flow learns more about `foo`. It starts out having to be | |
// one of two things, then as we pass the first two cases, we rule each of them out by turn. By the time we get to the default | |
// case, `foo` can't be either of the distjuncts, so it falls back to the base type: any. And any can be a string, so it works. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment