jsigbiz / spec

JavaScript signature notation
130 stars 6 forks source link

Avoid the bad parts of typescript. #37

Open Raynos opened 10 years ago

Raynos commented 10 years ago

There is an article about "the bad parts of typescript" by @j201 ( http://j201.github.io/posts/2014-08-30-TypeScript-The-Bad-Parts.html ).

I think typescript is a very interesting piece of prior art for jsig just liked jsdoc is. We should ensure that we do not suffer the same faults as predecessors.

I think it's worth a discussion on how to avoid the following problems:

And any other problems that might be common in typescript.

Raynos commented 10 years ago

Inflexible unions

I think we've solved this with the | operator.

We can say that type Either<T> : Error | T

Lack of higher kinded types

I'm not sure if we support higher kinded types.

type Functor<Box<T>> : {
  map: (this: Box<T>, (T) => U) => Box<U>
}

I think it could be possible but no-one has drafted how this would work yet nor is it in the parser.

Inability to model real world JS values.

We can model tuples with foo : [Number, Number]

We can also model complex libraries like

map : (
  (
    arr: Array<T>,
    cb: (T, Number) => Array<U> | U
  ) => Array<U>) &
  (
    obj: Object<String, T>,
    cb: (T, Number) => U
  ) => Object<String, U>

faulty type system

jsig currently does not have nullables by default. The only way null is valid is to use type Foo : Number | null in which case we can infer that the null branch is unhandled.

verbose function syntax

jsig has nice terse syntax for functions foo : (A, B) => B with no overloading, there's only one way to define a function.

lack of flexible aliases

jsig supports full type aliases with the type Foo : {{some expression}} syntax. You can give anything a name that may or may not be generic. for example type Foo : String or type Bar<T> : Array<T>

clunky intersection syntax

we use generic syntax like & to represent intersections. We dont use non composable syntax like an interface keyword or a specific extends keyword.

For interesting multiple things you can just do A & B & C

junosuarez commented 10 years ago

Lack of higher kinded types

we can easily punt by saying that the annotation syntax supports it. the blog post you link uses essentially the same syntax to express their point. Where TS falls down is in their type inference system. Similarly, for jsig, this wouldn't be a syntax issue but an inference issue. I lack the necessary expertise to comment intelligently on what this would entail or what else it might imply for jsig, but I would say that since it is logically sound throughout and straightforward enough for a human to understand what is going on, then this is a scenario we should support. The syntax you propose, wherein you bind the type of this and say that it has a map method, seems like a good way to describe a Mappable.

Failure to Model JS Values

This is the one that gives me pause. JavaScript is so flexible that it's not necessarily possible - or even desirable for our purposes - to model every possible value. As the linked post mentions, using arrays as tuples, or objects as dictionaries, gets tricky to model, especially when you begin adding other constraints such as property names, array lengths, etc. We've added a few of these modelling features into jsig (in every instance, with concrete use cases); I'd be hesitant to add more complex modelling expressiveness and constraints without compelling use cases just in the name of completionism.

Faulty Type System

The linked post brings up the conflation of null and undefined and other types. We addressed this a bit in removing nullable syntax (Type?) in favor of explicit unions (Type | void), but I think we should think through this further and make sure that we're doing the right thing.

Annoying Type Syntax (Functions)

This is basically the argument made earlier about the JS quirkiness around defining things that are both invokable functions and objects. For all the lipservice paid to first-class functions in JavaScript, functions sure do get a lot of strange separate-casing. Again, I like the solution we came up with to address this explicitly using type unions although I'll mention again that we have a large wart due to union operator associativity

No Type Aliases

well, we have 'em, at least per my reading of the spec and the use of jsig's type keyword

clunky intersection syntax

agreed, this is basically what we already do