I agree, the next missing bit is runtime structural typing (not optional of course) that allows constructs like:
```
const whatIsFoo = match (foo) {
case : nil : "nothing, really"
case : string : "it's a string"
case : number | boolean : "it's bool or number"
case [ head, ...tail ] : string[] : `it's array of strings with head ${head} and tail ${tail.join(', ')}`
case { value } : { type: 'NodeFoo' } : `it's Node Foo with value ${value}`
default: "well, something else."
It kind of already feels like that's what Objective-C is. You can use pretty-strong types, or you can just cast to id. Same with NSArray, elements can either be id (default) or a specific type. I just kind of feel like using better type systems hasn't actually helped me write better/cleaner/safer code. It's just added a very small amount of confidence and sometimes convoluted my code disproportionately.
Optional, structural algebraic type system with runtime support (mainly for `match ...` constructs) is IMHO the sweet spot.
It really makes a difference to have it. The analogy on top of my head is this: it's like a difference, when working on text processing code, to have regexp or do things by hand. Similar to regexps, above type system support, can cut necessary code by orders of magnitude and make it much more readable/reason about.
```
const whatIsFoo = match (foo) {
}```