So lots of optionals might well be the better path here.
Let me do this:
const x: String | Int
Instead of enum MyEnum {
case string(String)
case int(Int)
}
There's an existing proposal for this here:https://forums.swift.org/t/re-proposal-type-only-unions/7270...
To understand the difference, `String | String` is just `String`. It's a union, not a sum type. There's no tag or identifier, so you cannot distinguish whether it's the first or the second string.
If this sounds pedantic, this has pretty important ramifications, especially once generics get involved.
type Option<T> = T | undefined
function f<T>(value: T): Option<T> { ... }
let thing: string | undefined = undefined;
let result = f(thing);
Now imagine the definition of Option is in some library or other file and you don't realize how it works. You are thinking of the Option as its own structure and expect f to return Option<string | undefined>. But Option<string | undefined> = string | undefined | undefined = string | undefined = Option<string>.The mistake here is in how Option is defined, but it's a footgun you need to be aware of.
At least with |, you're attempting to model the state space. You're saying "this is one of these things." You might get the exhaustiveness wrong, but you're in the right ballpark. As it's normally done right now, the Swift developer with five optional properties is modeling state as "maybe this, maybe that, maybe both, who knows, good luck." which is just worse than a bar. If you need to discriminate explicitly, add a `__kind` field!
let x: String | Int
switch x {
case let value as String:
// handle String value here
case let value as Int:
// handle Int value here
}
There's one more thing about TypeScript-style union types: string literals. I think it's great to be able to do type Options = "option_1" | "option_2" ... "option_n"
And subsequently I could use let t: Options
switch t {
case "option_1":
// handle `"option_1"` case here
...
case "option_n":
// handle `"option_n"` case here
}
I think this is more programmer friendly than requiring an out-of-line definition of a new `enum`. Sometimes you just want to write some code, you know?At the same time, how often do you really need (Just (Just (Just ...)))?
In what way? My understanding is they're widely used and encouraged.
If you actually try and write it all out (like go full-on and use TCA to model all the states and actions such that all and only valid states can be represented in the state types) the compiler is going to have a hard time, you're going to write masses of boilerplate, and just in general it's much rougher than zustand and expo.