> Single argument doesn't capture required/optional semantics.
I disagree. As shown here (section "Tuples and Structs")
http://gcanti.github.io/2014/09/29/javascript-types-and-sets.html
tuples and hashes are theoretically equivalent, but
I'd prefer to stick the required/optional semantic to the property:
var Person = struct({
name: Str, // required string
surname: maybe(Str), // optional string
email: maybe(Str) // optional string
});
rather than rely on an arbitrary order: `Person(name, [surname], [email])`, but it could be also `Person(name, [email], [surname])` or `Person([email], name, [surname])` ...
> I think a hybrid approach is best.
Without arguments, I'm forced to interpret it as an expression of taste, so I automatically and kindly agree with you.
> Also isn't discoverable, requires reading docs or source.
I disagree. The meta info of the `Person` type (name, surname, email)
are easily parseable (you don't even need esprima for that)
since they are expressed in vanilla JavaScript rather than opaque comments like JsDocs.
This is an example of what I'm saying:
http://gcanti.github.io/resources/tcomb-react-bootstrap/playground/playground.html
When you make a mistake I automatically display the docs.
The docs are generated on the fly analyzing a domain model written with the same style of the `Person` above.
IDE support is straightforward to obtain.
> Another option is fluent APIs.
I generally don't like fluent APIs:
- they are cumbersome for the developer designing the API
- they produce dangerous, temporary, intermediate, invalid type values during the construction
- required/optional semantic is a mess to implement since quite all properties must be temporary optional
- it's not clear when the building process can be considered terminated