Skip to content

reconsider TypeScript support #446

@davidchambers

Description

@davidchambers

Update (2017-10-03): I have updated chainCurriedFlipped to delay the introduction of B, as suggested by @gcanti. I have also updated the results to correct an unrelated error I made initially (providing arguments to chainCurriedFlipped in the wrong order).


@miangraham and I have been working on #431 for several weeks. We've made good progress despite the impedance mismatch between the two type systems.

I had trouble defining types for chain. To simplify the task I specialized the type signature:

chain :: (a -> Array b) -> Array a -> Array b

I couldn't get this to work. I asked for help in the TypeScript room on Gitter and @sluukkonen provided helpful responses (including a link to microsoft/TypeScript#17520). I learnt that certain combinations of removing currying, changing the argument order, and replacing id with x => x (!) would appease the compiler.

I defined four versions of “chain” to discover the magic combination:

const xss = [[1, 2], [3, 4], [5, 6]];

function id<A>(x: A): A { return x; }

function chain<A, B>(f: (x: A) => Array<B>, xs: Array<A>): Array<B> {
  return Z.chain(f, xs);
}
function chainFlipped<A, B>(xs: Array<A>, f: (x: A) => Array<B>): Array<B> {
  return Z.chain(f, xs);
}
function chainCurried<A, B>(f: (x: A) => Array<B>): (xs: Array<A>) => Array<B> {
  return xs => Z.chain(f, xs);
}
function chainCurriedFlipped<A>(xs: Array<A>): <B>(f: (x: A) => Array<B>) => Array<B> {
  return f => Z.chain(f, xs);
}

Results of applying functions to id and xss

Function Result Value/Explanation
chain Argument of type <A>(x: A) => A is not assignable to parameter of type (x: {}) => {}[].
chainFlipped [1, 2, 3, 4, 5, 6]
chainCurried Argument of type <A>(x: A) => A is not assignable to parameter of type (x: {}) => {}[].
chainCurriedFlipped [1, 2, 3, 4, 5, 6]

Results of applying functions to xs => xs and xss

Function Result Value/Explanation
chain [1, 2, 3, 4, 5, 6]
chainFlipped [1, 2, 3, 4, 5, 6]
chainCurried Argument of type (xs: {}) => {} is not assignable to parameter of type (x: {}) => {}[].
chainCurriedFlipped [1, 2, 3, 4, 5, 6]

My reactions to the tables above:

  • 😱 id and xs => xs are not equivalent
  • 😞 TypeScript does not like curried functions
  • 😠 TypeScript's limitations affect API design

I'm concerned that even if we succeed in approximating type classes with interfaces, complications such as these will make Sanctuary and TypeScript an awkward couple. What do others think?

Sanctuary was designed as a JavaScript library. Had we set out to create a functional programming library for TypeScript it's likely we would have done things quite differently. I'm concerned that treating both JavaScript and TypeScript as first-class targets will lead to compromises. I'd like to continue to focus on making Sanctuary a principled, capable JavaScript library. Perhaps the TypeScript type definitions should live elsewhere so TypeScript's limitations won't influence the design of our API.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions