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

Typescript Maybe<A> #649

Open
codingedgar opened this issue Sep 5, 2019 · 18 comments
Open

Typescript Maybe<A> #649

codingedgar opened this issue Sep 5, 2019 · 18 comments

Comments

@codingedgar
Copy link

Hi! Incredible library 👏 thank you 🙏

I'm using Sanctuary with Typescript (@types/sanctuary@0.14.2) and the type of S.Maybe is not exported, i copied the type and use it in my own folder and worked but the type itself is not very useful basically everything matches with it.

Is there any alternative for the typing of Maybe ? or any way i could contribute?

Thank you in advance 🙏

@davidchambers
Copy link
Member

I recall being unable to export the Maybe<A> type due to a name conflict with S.Maybe. I don't know whether there's a workaround for this problem (my TypeScript knowledge is limited). If you have a solution, please share it. :)

@codingedgar
Copy link
Author

What is the difference with S.Maybe why not use the same export as Maybe ? i fail to see the difference, sorry. It looks like they are the same thing.

@davidchambers
Copy link
Member

Haskell has polymorphic literals:

Prelude> 1 :: Int
1

Prelude> 1 :: Float
1.0

Haskell also has polymorphic functions:

Prelude> pure 1 :: [Int]
[1]

Prelude> pure 1 :: Maybe Int
Just 1

Note that the type of pure depends on the desired result type. In each of the expressions above the desired result type is explicitly stated, but in real code it is often inferred.

JavaScript has no type inference, so a function like pure needs to take an argument that indicates what the output type should be. The Sanctuary equivalent of pure is S.of:

> S.of
of :: Applicative f => TypeRep (f a) -> a -> f a

> S.of (Array) (1)
[1]

> S.of (S.Maybe) (1)
Just (1)

S.Maybe is a type representative, a JavaScript object of no special significance to TypeScript.

@codingedgar
Copy link
Author

codingedgar commented Sep 18, 2019

I see the difference now, thank you 😊 . What about doing something like Array does, it is a global type and a global constructor (TypeRep). Or using another namespace to export all the other types Maybe, Either, Bifunctor, etc.

declare module 'sanctuary' {

  interface Maybe<A> extends IOrd<Maybe<A>> {
    constructor: MaybeTypeRep
  }

  interface MaybeTypeRep extends TypeRep {
    '@@type': 'sanctuary-maybe/Maybe@1';
    'fantasy-land/of'<A>(x: A): Maybe<A>;
  }

  var Maybe: MaybeTypeRep;
  
}
import { Maybe } from "sanctuary";

S.of(Maybe) (1)

type someMaybe = Maybe<number>

with this typescript is able to tell when we're using the type Maybe<A> or the value Maybe, just like Array.

@davidchambers
Copy link
Member

The solution proposed in your edited comment sounds ideal, @edgarjrg! Could you submit the change to vicrac/DefinitelyTyped? That would get us significantly closer to releasing new type definitions. :)

@codingedgar
Copy link
Author

codingedgar commented Sep 18, 2019

The only problem I see is:

exports=S

With the previous propose we need to change from custom single object to ambien module , and export each function from Static

declare module "sanctuary" {
   export function of<A>(x: A) ...
   export interface SanctuaryStatic {
       of: typeof of
   }
}

Other solution would be

/// <reference path="Maybe.d.ts">
exports=S

That would make Maybe<A> globally available if @types/sanctuary is installed.

I incline for the ambient module, but the reference path/types are valid, especially is the type of maybe lived in santuary-maybe, then the reference type is inevitable. JQuery uses that strategy if you would like to observe a more involved example.

@mohsensaremi
Copy link

@edgarjrg Can you explain your solution a little bit more?
I read #649 (comment) and got the idea but I didn't understand what IOrd and TypeRep are and where should I import them.

@ghost
Copy link

ghost commented Dec 27, 2019

@mohsensaremi I had success with these changes to the index.d.ts (original index.d.ts is here).
That was the minimal effort to use Maybe as a type and as a value/TypeRep without the need to create a second Maybe interface in my own project.

I really just had a a couple of hours experimenting with the library and used an absolute minimum of features, so I don't know, if it works well enough or breaks somewhere. Maybe (pun intended :) someone else more experienced with sanctuary-js have a look over it.

If you want to test it, just copy paste the content in node_modules/@types/sanctuary/index.d.ts

@codingedgar
Copy link
Author

Hi ! @davidchambers @vicrac and I worked in this improvements in order to make available the types of maybe and others through ambient modules, we never finished the work, but would be nice to.

@codingedgar
Copy link
Author

@edgarjrg Can you explain your solution a little bit more?
I read #649 (comment) and got the idea but I didn't understand what IOrd and TypeRep are and where should I import them.

@mohsensaremi the types we're trying to make are based on this spec: https://github.com/fantasyland/fantasy-land , Maybe is compliant with some of those algebras (like Ord and Applicative) and we would like to make it explicit in the new types.

The point is that Sanctuary works with this algebras, so functions can be more composable, if I say that Maybe is an Ord, actually is compliant with all of this, that means i could apply functions like S.lt , and any other function that works with that algebra, to Maybe or to any other type that works with the algebra.

That's why for S.map is the same an Array or a Maybe, both implement the Functor algebra, meaning they both can map.

My solution had to do a bit more with how the type module of Sanctuary is build, with the current way it is impossible to export Maybe, as there is only one big object exported S, what i want to do is being able to export the Maybe type, and the Maybe constructor (TypeRepresentative) to be able to make Maybe objects and to type functions that accept and/or return Maybe type, and at the same time, type correctly Maybe, so it can take advantage of all the compatibility with Sanctuary functions.

@codingedgar
Copy link
Author

codingedgar commented Dec 27, 2019

This is the roadmap to finish the types, currently the PR that @vicrac open is closed by now, and I didn't had more time then to continue, but it would be nice to finish.

@mohsensaremi
Copy link

mohsensaremi commented Dec 27, 2019

@edgarjrg Can I use this fork https://github.com/vicrac/DefinitelyTyped/blob/master/types/sanctuary/index.d.ts now?
I have copied this file in my customTypes/sanctuary/index.d.ts but it is not working.

@codingedgar
Copy link
Author

You could, not all functions are typed, but it should be compatible with everything, it’s just typings.

@mohsensaremi
Copy link

@edgarjrg

const x: Maybe<number> = Just<string>("X");
const y: Either<number, number> = Left("X");

These statements should throw error but the code is compiled successfully.
Am I doing somethings wrong?

@codingedgar
Copy link
Author

@mohsensaremi i'm looking into it.

It looks like some kind of TypeScript soundness issue about generics, might be related to https://github.com/Microsoft/TypeScript/wiki/FAQ#why-is-astring-assignable-to-anumber-for-interface-at-- .

@mohsensaremi
Copy link

@edgarjrg
Thanks for your respond.
Are you going to fix it soon or should is search fo other alternatives?

@codingedgar
Copy link
Author

@mohsensaremi you can try now from this commit I added your use cases as tests and improved a bit the types.

This is not a done job at all, the library however works perfectly ignoring TypeScript if you just want to do that, the runtime checks of Sanctuary are far more advanced and safe than TypeScript at this point.

You can also try https://github.com/gcanti/fp-ts/ I found those types more robust for TypeScript, but there's no actual runtime garantes like the ones provided by Sanctuary.

And for the record i'm just a regular person that's trying to help this great project with nothing in return like everybody else, it's frown upon to ask for quick fixes, but no worries, I know you say that with the best intent in mind ✌️

@davidchambers
Copy link
Member

I second the fp-ts recommendation (for TypeScript projects). 👍

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

3 participants