Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TS/flow typings? #254

Open
KiaraGrouwstra opened this issue Sep 11, 2016 · 45 comments
Open

TS/flow typings? #254

KiaraGrouwstra opened this issue Sep 11, 2016 · 45 comments

Comments

@KiaraGrouwstra
Copy link

KiaraGrouwstra commented Sep 11, 2016

Gitter:

@tycho01: afaict, there have not been attempts yet to write up TypeScript definitions for Sanctuary, correct? Has this just not been on the radar so far or might it be problematic with their type system?
@davidchambers: More the latter I would say, @tycho01. I don't think it's currently possible to express types such as Functor f => (a -> b) -> f a -> f b in TypeScript. That said, @gcanti is doing things with Flow in https://github.com/gcanti/flow-static-land that I didn't think possible, so there's hope. :)

I was thinking it might be useful to put this out here, so we could consolidate questions/issues and perhaps check for solutions with the TS/flow team.

Potentially relevant (TS):

@KiaraGrouwstra KiaraGrouwstra changed the title TS typings? TS/flow typings? Sep 11, 2016
@davidchambers
Copy link
Member

I'm very interested to see this. It's not something I plan to work on at this stage as I'm focused on the existing modules (sanctuary, sanctuary-def, and the nascent sanctuary-type-classes). I'm happy to be involved in the exploration if someone would like to lead it. :)

@KiaraGrouwstra
Copy link
Author

Edit: some complications have been listed out by Isiah Meadows here:

First, no type checker (TypeScript, Flow, or any other) can fully check the core language (most notably bind, apply, call, and Object.assign).

Second, they both still are missing some pretty significant features required for typing common JavaScript idioms (higher kinded types for Fantasy Land and Ramda users, variadic generics for bind, call, and apply, n-ary unions for Object.assign and similar, etc.).

@mnn
Copy link

mnn commented Nov 7, 2016

Oh, that's unfortunate. I was quite excited about this library. Sadly, without (even bad) TS typings I cannot use it (employer won't pay me for writing typings). 😢

@davidchambers
Copy link
Member

@mnn, I bet others would contribute if you were to start writing the TypeScript type definitions. 😄

@mnn
Copy link

mnn commented Nov 7, 2016

Well, I am pretty sure I am not an ideal candidate - started learning TypeScript very recently and my knowledge of Sanctuary is limited to a brief browsing of your docs. 😑

But I'll try! 😄 Started working on it over there - https://github.com/mnn/typings-sanctuary.

@davidchambers
Copy link
Member

That looks like a good start, @mnn!

@jonahx
Copy link

jonahx commented Nov 16, 2016

This is promising, but given that TS support seems to be bleeding edge right now, i'm curious how others are dealing with this in projects? Are you simply using sanctuary's runtime type checks as an alternative to TS/flow?

@KiaraGrouwstra
Copy link
Author

I imagine the alternative to compile-time guarantees has largely been
ensuring high code coverage as an alternate method of locating problems.

On Thu, Nov 17, 2016 at 3:43 AM, Jonah notifications@github.com wrote:

This is promising, but given that TS support seems to be bleeding edge
right now, i'm curious how others are dealing with this in projects? Are
you simply using sanctuary's runtime type checks as an alternative to
TS/flow?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#254 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC6uxXSGkTAeFiAQQXJ9Gg8n0J9dzj9Mks5q-1zNgaJpZM4J539I
.

@davidchambers
Copy link
Member

I have only used Sanctuary in vanilla JavaScript projects. My experience is consistent with your imaginings, @tycho01: the combination of run-time type checking and unit tests catches many type errors.

@mnn
Copy link

mnn commented Nov 17, 2016

@jonahx TS support is definitely not ready, in current state I don't recommend using it for anything serious (there is not merged major change). But I am nearing finish line, I hope next week I'll be able to complete it.

It won't be perfect, because (I think) some types are just not possible to capture by TS type system (like TypeRep and meld 😓) and some things TS is not able to infer on its own (Nothing() Nothing<number>()). Also I had a hard time with the combination of module object with presence of create (typed as module object) - I doubt that it can be done in ES6 imports (without duplicating whole interface for the library).

@davidchambers
Copy link
Member

I'm pleased to hear you've been making good progress, @mnn. :)

By the way, meld was removed in #280 so won't cause you problems for much longer. I understand that create is difficult to handle. Let me know if you think of a change we could make to Sanctuary that would make things easier at your end.

@mnn
Copy link

mnn commented Nov 17, 2016

After many not working attempts I ended up with this create/module prototype (type in first case is not required). It's not ideal, but I can't think of any way how to improve it. I hope next week I'll update real typings according to this scheme and finish Either.

meld looks really interesting, but as you wrote in the other issue, it doesn't seem to fit many real problems. Glad you mentioned it, I was already thinking about writing some script to generate typings for it, similarly as I did for super useful pipe (I really didn't write that pile of typings by hand 😄).

@KiaraGrouwstra
Copy link
Author

Whoa :), might it be possible to publish on npm @mnn?

@mnn
Copy link

mnn commented Nov 18, 2016

After the update I'll look into it (never done it before, but from the link you posted it seems relatively easy).

Another possibility would be to include the typings in the Sanctuary repository (that's the preferred way, but not always possible - not every JS library wants TS typings bundled). IIRC there were some issues with versioning when publishing standalone typings. Bundled typings work out-of-box and are always for the right version because the typings and the library are distributed together. Downside is a slightly larger library package (not resulting JS, only package), but only by a few kilobytes (in our case I guess like 30KB).

@davidchambers
Copy link
Member

Another possibility would be to include the typings in the Sanctuary repository (that's the preferred way, but not always possible - not every JS library wants TS typings bundled).

I'm certainly open to this possibility, but I'll need to learn about the pros and cons. It also strikes me as a good idea to have people use your package for a couple of months, @mnn, before potentially opening a pull request to add the typings to the Sanctuary repository.

@gcanti
Copy link

gcanti commented Nov 18, 2016

Hi all,

I wrote a first draft of the definition file for Flow, you can find it here.

Contributions, tests and PRs are warmly welcomed.

@davidchambers
Copy link
Member

Very cool, @gcanti!

@gcanti
Copy link

gcanti commented Nov 19, 2016

As a side note, @davidchambers and all the contributors, thanks for the awesome documentation, I know is a tremendous effort. Precise signatures and many examples are very helpful when you write a definition file.

@KiaraGrouwstra
Copy link
Author

@mnn: would you mind commenting on the script you used for the pipe function there? This sounds like it could be useful...

@mnn
Copy link

mnn commented Nov 29, 2016

@tycho01 It's available at the repo - https://github.com/mnn/typings-sanctuary/blob/8f05ba2f87c3fa1de9462e7fb4e788b5610f6266/scripts/Pipe.hs. I am still learning Haskell, so the code is probably far from ideal. It surely could have been written in something like JS or Ruby, but I wanted to finally use Haskell for something real and useful, not just for exercises 😄.

Or do you mean describing how it works (sorry, English is not my native language)?

@KiaraGrouwstra
Copy link
Author

@mnn That's fine, was just curious. Thanks. :D

@KiaraGrouwstra
Copy link
Author

@mnn my attempt in Ramda in the meanwhile:

letters = (idx) => (n) => R.range(idx, idx + R.clamp(0, 26, n)).map(i => String.fromCharCode(i))
upper = letters(65)
lower = letters(97)
[lows, ups] = [lower, upper].map(f => f(25));
zipped = R.zip(lows, ups);
`export function pipe<${ups.join(', ')}, Z>(functions: [(a: A)=>${zipped.splice(1).map(([low, up]) => `${up}, (${low}: ${up})=>`).join('')}Z]): (a: A)=>Z;`
// export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z>(functions: [(a: A)=>B, (b: B)=>C, (c: C)=>D, (d: D)=>E, (e: E)=>F, (f: F)=>G, (g: G)=>H, (h: H)=>I, (i: I)=>J, (j: J)=>K, (k: K)=>L, (l: L)=>M, (m: M)=>N, (n: N)=>O, (o: O)=>P, (p: P)=>Q, (q: Q)=>R, (r: R)=>S, (s: S)=>T, (t: T)=>U, (u: U)=>V, (v: V)=>W, (w: W)=>X, (x: X)=>Y, (y: Y)=>Z]): (a: A)=>Z;

I've done a terrible job at switching to Haskell so far :P, being in front-end really isn't helping...

@safareli
Copy link
Member

I think you can also use numbers (with letters) for type variables pipe<T1,T2...

@KiaraGrouwstra
Copy link
Author

@safareli: Yeah, that does appear to be method currently using in the typescript-ramda typings. I'm currently trying to see if I can improve those a bit more with generation like that...

@raveclassic
Copy link

@mnn Hi, do you have any success with the typings? Maybe you could push them to npm @types?

@KiaraGrouwstra
Copy link
Author

@mnn I've created an empty repo at https://github.com/types/npm-sanctuary now. I think @blakeembrey could provide you with direct push access.

@mnn
Copy link

mnn commented Jun 29, 2017

For older version types are for almost everything, but because of limitations of definitely-typed import script it can't be published there.

Types for newer version are currently not really being worked on. (I started in my free time, but I am not sure if/when I finish it; I am only using TS+Ramda+Sanctuary at work and they don't seem to agree to pay for updating typings. Last time it took me several work days to type most of Sanctuary, also this time there is much more type-class things which will be difficult or even not-typable b/c of TS limitations.)

If you want better solution than local package you could try typeRoots TS compiler option and add a package pointed at github repo. I haven't tried it yet, it might not work at all.

@raveclassic
Copy link

raveclassic commented Jun 29, 2017

Thanks, awesome work guys btw!

@mnn I tried both pointing to github repo and localpackage, none of them worked. But I'm sure I did something wrong, I'll try again.

even not-typable b/c of TS limitations

Latest TS versions (>= 2.2) bring significant improvements to typing, maybe it could help.

@mnn
Copy link

mnn commented Jun 29, 2017

I tried both pointing to github repo and localpackage, none of them worked. But I'm sure I did something wrong, I'll try again.

At work we are using the local package way (not only for Sanctuary) and it's working alright. Make sure that index.d.ts (and other files from sanctuary directory [from my repo] as well as its fake package.json) is in local_packages/typings-sanctuary. After you do this you have to run npm i to allow it install local packages.

Latest TS versions (>= 2.2) bring significant improvements to typing, maybe it could help.

TS recently released 2.4, it should improve inference with generics (I haven't tested it, but it would be great if S.Nothing<number>() would no longer require <number>). But I am afraid full typing of Sanctuary won't be possible, at least support for higher-kinded types is necessary (and even then some specialties might not be possible, but that would only be a few cases not like now - dozens of missing, bad or very limited typings).

@KiaraGrouwstra
Copy link
Author

@mnn:

support for higher-kinded types

related

I'm not sure if 2.4 will help you much over 2.2 for inference by the way. Generic degeneration is still there.

@raveclassic
Copy link

Thanks for the answer!
I'm only starting to integrate ADT in my team and, as we are heavily using TS, I'm looking for an appropriate solution which will be up to date (I mean avoiding manual continuous updates) with the base codebase.
Relying on practice, I'd like to use something which is written in typescript from ground, like fp-ts.
Could use please say smth about it? Is it worth integrating or are there any far-reaching plans to bring ADT to TS in terms of sanctuary?

@davidchambers
Copy link
Member

Could use please say smth about it?

I'm not sure who you were asking. I don't think it was me. Please correct me if I'm wrong. :)

@raveclassic
Copy link

raveclassic commented Jun 30, 2017

Guys you all are doing awesome work! All your opinions would be great :)

I'm really impressed with sanctuary and especially how it is aligned with haskell. But I'm trying to find a Long-Term-Service solution...

EDIT: (In terms of TypeScript)

@davidchambers
Copy link
Member

I'm not a TypeScript user. I don't know whether Sanctuary is a good choice for a TypeScript project. I understand that depending on Sanctuary in a TypeScript project is currently somewhat risky as it necessitates an additional dependency on a separately maintained typings package.

If Sanctuary is to work with TypeScript at all we should eventually provide the typings directly, so TypeScript users would always have access to the same Sanctuary versions as JavaScript users.

@KiaraGrouwstra
Copy link
Author

@raveclassic: one consideration there may be inference quality. I haven't used either much though it should be easy to try a Maybe from both to get a sense. Then again, once a problem has been solved in one, we'd also know how to solve it in the other.

That said, you may also consider current differences in focus. If Sanctuary is still more focused on run-time checks, that may add extra value if you are to check data coming in over the wire from APIs (alternatives there being e.g. JSON Schema).

There seem to be other differences as well, with FP-TS focusing on ADTs while Sanctuary patches some basic functions, offering e.g. a safe head. In that sense, you might consider them complementary. Better yet, both claim conformance with the Fantasy Land spec, so you may not even need to care which Maybe is from where.

I've personally found myself not using ADTs much yet in JS/TS -- I'm currently feeling somewhat excited about further trying partial.lenses as the next step from Ramda that also kinda seems to take care of safety. That said, not much progress with TS over there so far -- even in Ramda type inference for R.path itself is still WIP. So yeah, not the time to type traversals yet...

@mnn
Copy link

mnn commented Jun 30, 2017

My two cents:

Previous version of Sanctuary was typed for most part, sadly typings never made it to the official repo. Not sure in current version will be/would be something different...

Also it seems really wild and not supporting previous releases. Current version removed dozens of methods (essentially breaking majority of code interacting with Sanctuary in our codebase), so if I ever update I would have to either update all occurrences with a new static variant (probably won't happen, because TS in this case has much worse type inference than with methods) or write wrappers for all removed methods (sounds very tedious, not sure if it can be automated). I would like to see something like what e.g. Angular does - they still support older version and propagate important fixes back. In case of Sanctuary it's crashing on circular data structures which forced me to disable runtime checks in dev build (without this Sanctuary is not that different compared to other libraries).

Because of these issues I am no longer so sure about choosing Sanctuary for our project at work. Sanctuary has quite a lot of people using it (compared to TS variants), but usage from TS is not great in quite a lot of cases (e.g. mentioned S.Nothing() not working as expected unless you provide type parameter) which with last update got even worse (static variants of functions for data types are usually not inferred, so one has to provide type parameters manually - adds a lot of boiler plate).

Since it seems that I won't be working on the typings (other folks doesn't seem to contribute much, IIRC I had like 2 PRs with minor fixes; maybe at the end of summer I might get to it, but it depends on my employer), I can't recommend new TypeScript projects to use Sanctuary. If you are really considering using it, try using it first in some test project - e.g. in previous S version I was missing several things like something like bimap and I really hated having to specify type parameters in pipe when creating function from it (TS doesn't infer type parameters from usage [so we have literally full lines of type parameters for pipe calls], or at least in previous version it didn't).

@gcanti
Copy link

gcanti commented Jun 30, 2017

Better yet, both claim conformance with the Fantasy Land spec

Just a clarification, fp-ts is not (and won't be) fantasy-land compliant (is just inspired by)

@raveclassic
Copy link

Thanks for your answers! Will try to figure out which way fits best for the team.

@timhuff
Copy link

timhuff commented Jul 27, 2017

Hi everyone. Just started using Sanctuary - really nice work. I use VSCode as my IDE and this issue is resulting in me losing intellisense on all my Sanctuary-based functions. It appears that this issue was mostly solved at one point by @gcanti's libdef but then the library underwent a dramatic change and that libdef became obsolete. Since then, there's been no updated libdef. Am I understanding this correctly? Does anyone have even a partial solution to this issue that's compatible with the current version of Sanctuary? Thanks

@davidchambers
Copy link
Member

I'm working on TypeScript type definitions for inclusion in an upcoming release. Have a look at master...davidchambers/typescript if you're interested in seeing my progress.

@KiaraGrouwstra
Copy link
Author

Looks like someone converted! :)

It looks pretty good overall. I haven't tried them, but lemme try and list the little bits of feedback I can think of:

  • esp. binary fantasy-land methods lack currying
  • As your internal _Maybe appears to function as a constructor, I wonder if for TypeRep typing you'd have use for the constructor-based version I'd used in mnn's typings. Disclaimer haven't tried. This could need ES6 classes, I dunno.
  • Potential room for improvement using literal type inference for e.g. type guards. Yeah, none of that exists in haskell. not exactly high priority either. Given the above point (maybe needing classes?) that way is could make use of the type-level is (e.g. tutorial pet is Fish in above link) to discriminate the boolean values.
  • On the comparative functions:
    • Why are there A generics when not used?
    • For Ramda we'd put the different ordinal types in one ordinal type (union), then put that in a generic such that it'd automatically use the same one in both parameter positions so you wouldn't need to repeat the typing. (I guess the fantasyland Ord params wouldn't necessarily require matching such that they'd use the same fantasyland Ord implementation though.) I just realized this approach might fail given type literals though, so in that sense your approach may be safer. In current TS I can't even think of a good fix to make this DRY again. Maybe that gets slightly better when we have type-level type-checks.
  • Array typing on map precludes input from alternative implementations including Immutable.js's List. In the Ramda typings we addressed that by basing input requirements on ArrayLike (see the definition of that), though outputs there are still just regular arrays. Couple more occasions on other functions.
  • If Proposal: Get the type of any expression with typeof microsoft/TypeScript#6606 landed, I believe types like NonZeroFiniteNumber etc. could likely be properly expressed through type constraints. I appear to rarely shut up about wanting that added to TS, I know. I think isiahmeadows had had a proposal for constraint functionality as well though, mentioned in there somewhere. Constraints for Integer would also need either official recognition or type-level arithmetics. (To calculate type-level i % 1 == 0 -- I did a type-level modulo, but its internal addition/subtractions works only on whitelisted integers meaning it couldn't distinguish fractions from integers off the list.)
  • In parseJson<A, B>(pred: (A) => boolean, s: string): Maybe<B>, the A generic is completely counter-productive. To get a useful type back you need to manually supply B to this function, meaning the current typing forces you to also explicitly provide a separate A, which is not even used anymore except in anymore except to constraint the predicate. I believe that also failed by the way -- Github's IDE colors the A in (A) => boolean as a variable rather than a type, which I believe correctly reflects how TS sees this (unlike Scala/Haskell). From your parseJson usage example though, the predicate appears not to have parameters?

Honestly it looks pretty solid as-is already though, and I'll concede that type-level type-classes are not really within my experience.

@ikatyang
Copy link

ikatyang commented Jul 30, 2017

Looks like you need some tools to test types:

  • run typescript compiler directly
    • impossible to write failing tests
  • dts-lint (DT tests this way)
    • behave as linter rule
    • failing tests avaliable ($ExpectType type, $ExpectError ErrorMessage)
  • typings-checker
    • one time test, output results
    • failing tests avaliable ($ExpectType type, $ExpectError ErrorMessage)
  • dts-jest
    • watching mode avaliable, using snapshot testing from jest
    • failing tests avaliable (@dts-jest:pass, @dts-jest:fail)
    • actual tests avaliable (//=> value)
    • can generate diff-friendly file for comparing

@tbsvttr
Copy link

tbsvttr commented Apr 21, 2021

Is there any progress on this?

@davidchambers
Copy link
Member

Despite significant effort, I have not succeeded in making Sanctuary and TypeScript play nicely together.

I use TypeScript at work, with fp-ts. TypeScript provides a lot of value to the team, despite its many imperfections. fp-ts is a fantastic library; I highly recommend it. The only thing that frustrates me is TypeScript's naive type inference, which sometimes forces me to redundantly specify a type or to replace f (x) with pipe (x, f).

I am motivated to make Sanctuary an even better library for functional programming in JavaScript. To those using TypeScript, I recommend trying fp-ts. :)

@tbsvttr
Copy link

tbsvttr commented Apr 22, 2021

@davidchambers Thanks for this helpful, clear, and quick reply!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants