Open eczn opened 7 months ago
Records are anonymous primitive compound value, use a structural check (test fields and types) instead of a nominal check (instanceof
). They are closer to string values than class instances.
Your example would be:
function handlePoint(x) {
if (isPoint(x)) {
console.log(`x is a point:`, x)
} else {
throw new Error(`x is not a point`)
}
}
function isPoint(x) {
return typeof x === "record" && typeof x.x === "number" && typeof x.y === "number"
}
There are many runtime or compile time libraries to help with type checking, this is out of scope for this proposal in my opinion. The Pattern Matching proposal may be a better place to discuss such feature.
Having an "is same structure" predicate could be interesting, but the exact semantics would be tricky.
For example, taking #{foo: #[ 1, false ] }
as an example.
First, should such a predicate recurse into values that are R/T? Aka, should it check the structure of .foo
?
Then if it does, what should it do regarding non R/T values? Should it compare them by value, by type, or not at all? If not at all, any tuple of length 2 for foo
would pass. If by type, it's need to be a tuple of [number, boolean]
. If by value, should there be a difference if the value is forgeable (string, number, bool, null?, registered symbol) or unforgeable (unique symbol, objects if they're allowed).
Comparing structure deeply by type of the leaf values might be a good compromise. Then you could implement the isPoint
above simply as const isPoint = x => isSameStructure(#{ x: 0, y: 0 })
Comparing structure deeply by type of the leaf values might be a good compromise.
This is still type checking, but the type is defined with a "template" value. This feels like a needless extra indirection when you could have const isPoint = x => isType(x, RecordType({x: NumberType, y: NumberType}))
. A downside of this indirection is that it forces dummy values (0
in your example) and prevents finer type constraints (literals, unions, etc.)
The main issue is what you described: the semantics are not clear cut. Answering the semantics means defining a type system for JavaScript (beyond typeof
or instanceof
).
TC39 is very far from being ready to standardize on a type system that can be checked IMO. Type Annotations is related when going in this direction. Reserving type syntax for custom use means that a standard type system would have to coexist with it, making it a bit harder to get.
try to name
#{ x, y }
:or: