Interesting, except you're redefining the type of "name" in each each class by specifying "string". Also, Clojure.spec allows you to be much more precise about properties. For example, it must be a certain length, non-nil, or even match a regex (e.g. first letter starts with uppercase).
What do you mean by redefining? I'm not redefining the type of "name". If you want to get compile-time checking that `Person` implements `Named`, you can use `class Person implements Named`.
Even better than that, you don't need to use classes, you can use "normal" JS data structures. Extending the last example:
const john = {
name: 'John',
age: 25
} // No class involved
f(john) // compiles
const alice = {
age: 25
firstName: 'Alice',
lastName: 'Jones'
}
f(alice) // compile-time error
Clojure.spec is cool, but I don't see how that is incompatible with static typing. You can still have libraries that check more complex properties at runtime.
EDIT:
> Also, Clojure.spec allows you to be much more precise about properties. For example, it must be [...] non-nil [...]
TypeScript also handles nulls in the type system:
function f(x: string | null) {
if (x != null) {
// tsc knows that inside this if, x can't be null
return x.length
} else {
console.log(x.length) // this doesn't compile, x is of type null here
}
}
And now imagine if you wanted to accept either an email or last-name (notice it does not match our person spec). Attempting to use interfaces would quickly get out of control. You'd have to create an interface for every single property and extend interfaces to form arbitrary groups of properties.