It would be nice to support matching on types:
let myVar = ...
case (myVar) {
when Number -> 'A number'
when String -> 'A string'
when Array -> 'A list'
when Object -> 'An object'
when undefined -> 'Nothing'
when _ -> 'Something else'
}
3 instanceof Number is false, how would you describe the comparison being applied here? How would that extend to custom constructors?
3 instanceof Numberis false,
instanceof is what I had in mind, but your counter example shows its limitations
instanceof also doesn鈥檛 work cross-realm, so it might not be the best default mechanism for any matching.
Maybe this is a follow-on proposal (and I feel like I may have see this proposed somewhere), but seems like a good place for a "Symbol-method" solution?
Another use case for @mAAdhaTTah鈥檚 idea of Symbol.whenPredicate (or similar): matching a string against regular expressions.
i'm not sure the suggestion will improve ease-of-debugging (or prevent footguns) over just explicitly matching typeof:
/*jslint devel*/
"use strict";
function foo(myVar) {
switch (typeof myVar) {
case "number":
return "A number";
case "object":
if (Array.isArray(myVar)) {
return "A list";
}
return "An object";
case "string":
return "A string";
case "undefined":
return "Nothing";
default:
return "Something else";
}
}
console.assert(foo(1) === "A number"); // true
console.assert(foo([]) === "A list"); // true
console.assert(foo({}) === "An object"); // true
console.assert(foo(null) === "An object"); // true
console.assert(foo("hello") === "A string"); // true
console.assert(foo(undefined) === "Nothing"); // true
console.assert(foo(Symbol()) === "Something else"); // true
I'm not sure how one would disambiguate between when TypeName and when identifier (with the latter matching anything and binding it to the identifier in the scope of that branch).
I.e., why wouldn't when Number -> match anything and bind it to Number, or conversely, why wouldn't when _ -> try to match against a type _ (which is a perfectly fine identifier)?
Also, what if myVar is the actual Number constructor?
In this case, why not match for Object.constructor?
let myVar = ...
case (myVar) {
when { constructor: Number } -> 'A number'
when { constructor: String } -> 'A string'
when { constructor: Array } -> 'A list'
when { constructor: Object } -> 'An object'
when undefined -> 'Nothing'
when _ -> 'Something else'
}
Or more readable:
let myVar = ...
case (myVar.constructor) {
when Number -> 'A number'
when String -> 'A string'
when Array -> 'A list'
when Object -> 'An object'
when undefined -> 'Nothing'
when _ -> 'Something else'
}
Or including value access while readable:
let myVar = ...
case ([myVar.constructor, myVar]) {
when [Number, _] -> 'A number'
when [String, _] -> 'A string'
when [Array, _] -> 'A list'
when [Object, _] -> 'An object'
when undefined -> 'Nothing'
when _ -> 'Something else'
}
@JorisBlanken because constructor matching is very unreliable and doesn't work across realms. It's the reason Array.isArray was created, and one should always use it over instanceof Array (and why instanceof should also be avoided)
Closing in favor of https://github.com/tc39/proposal-pattern-matching/issues/117
Most helpful comment
Also, what if
myVaris the actualNumberconstructor?