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

Example doesn't seem to work #24

Closed
vcanadi opened this issue May 20, 2021 · 9 comments
Closed

Example doesn't seem to work #24

vcanadi opened this issue May 20, 2021 · 9 comments

Comments

@vcanadi
Copy link

vcanadi commented May 20, 2021

The example with type D doesn't seem to work on the type alone (without given type params).
Similar behaviour (same error) happens with more simple example from tests:

data HigherKind a = HigherKind { higherKindList :: [a] }
$(deriveTypeScript A.defaultOptions ''HigherKind)
$(deriveJSON A.defaultOptions ''HigherKind)

main :: IO ()
main = putStrLn $ formatTSDeclarations $ getTypeScriptDeclarations (Proxy :: Proxy HigherKind)

which results in:

app/Main.hs:31:42: error:
    • No instance for (TypeScript HigherKind)
        arising from a use of ‘getTypeScriptDeclarations’
    • In the second argument of ‘($)’, namely
        ‘getTypeScriptDeclarations (Proxy :: Proxy HigherKind)’
      In the second argument of ‘($)’, namely
        ‘formatTSDeclarations
           $ getTypeScriptDeclarations (Proxy :: Proxy HigherKind)’
      In the expression:
        putStrLn
          $ formatTSDeclarations
              $ getTypeScriptDeclarations (Proxy :: Proxy HigherKind)
   |
31 | main = putStrLn $ formatTSDeclarations $ getTypeScriptDeclarations (Proxy :: Proxy HigherKind)i
@thomasjm
Copy link
Contributor

Oh, after some recent changes you need to include the type parameter. So Proxy :: Proxy (D T) or Proxy :: Proxy (HigherKind T). For multiple params you can do T1, T2, etc. Sorry, I need to update the docs.

@vcanadi
Copy link
Author

vcanadi commented May 20, 2021

Thanks. I noticed that this is the intended usage from the tests, but I was unsure since I didn't manage to get it working in my code (not the one mentioned above).
What I need is a higher kinded type parameter. e.g.

data X f = X (f Int)

Is this possible?

@thomasjm
Copy link
Contributor

Yes, it's possible as long as when you call getTypeScriptDeclarations you fill in f with something such that you get a reasonable type to map to TypeScript. For example, see the tests in TypeFamilies.hs under the heading "Complicated Beam-like user type".

Somewhat related to this, there is special built-in support for type families, when get mapped to TypeScript lookup types. You can also see that in the TypeFamilies.hs tests, somewhat mixed together with the other higher kinded stuff. I need to write that up properly as well.

@vcanadi
Copy link
Author

vcanadi commented May 21, 2021

Could you write an simple example of what to pass to my X type for f argument in getTypeScriptDeclaratios? I tried making a type TtoT similar to yours T, but I didn't manage to get it to work.

@thomasjm
Copy link
Contributor

data X f = X (f Int)
$(deriveTypeScript A.defaultOptions ''X)

-- Unfortunately we need to declare this funny instance because the constraints on
-- getTypeScriptDeclarations are a little too tight in this case
instance TypeScript (HashMap String) where
  getTypeScriptType _ = "void"

decls = getTypeScriptDeclarations (Proxy :: Proxy (X (HashMap String)))
> putStrLn $ formatTSDeclarations decls
type X = IX;

type IX = {[k: string]: number};

@vcanadi
Copy link
Author

vcanadi commented May 21, 2021

So is this something like making and typescript type for a "subtype" Y of X where
type Y = X (HashMap String) but HashMap String is arbitrarily chosen and it could be any * -> * type like Identity or Maybe as well?
As I understood, now the f as a type argument doesn't exist in TS? So it's just like a type without an argument, but I got to chose the specification (HashMap String) in Proxy (X (HashMap String)))
it possible that f remains unchosen so it remains a higher level type argument (or some hacky equivalent of it) in the TS?

@vcanadi
Copy link
Author

vcanadi commented May 21, 2021

My ultimate goal is to have this type in haskell:
data AlterList a b c d n = AlterList (a n) [(b n, c n)] (d n) (c n)
and have the TS equivalent without worrying to much about the TS (which I am not very familiar with)

@thomasjm
Copy link
Contributor

The part where you want f to remain unchosen sounds like you might want the closed type family stuff:

type family MyTypeFamily a = result | result -> a where
  MyTypeFamily Int = String
  MyTypeFamily String = Bool
  MyTypeFamily T = Int

data X a = X (MyTypeFamily a)
$(deriveTypeScript' A.defaultOptions ''X (ExtraTypeScriptOptions { typeFamiliesToMapToTypeScript = [''MyTypeFamily] }))

decls = getTypeScriptDeclarationsRecursively (Proxy :: Proxy (X T))
> putStrLn $ formatTSDeclarations decls
interface MyTypeFamily {
  number: string;
  string: boolean;
  T: number;
}

type IX<T extends keyof MyTypeFamily> = MyTypeFamily[T];

type X<T extends keyof MyTypeFamily> = IX<T>;

In general, TypeScript has a less powerful type system than Haskell, so it's hard to map your AlterList to TS generally, without knowing more about what a, b, c, d can be. But presumably you're also coming up with FromJSON/ToJSON instances, so that might help narrow down the types. (For example, a n couldn't be a function type.)

@thomasjm
Copy link
Contributor

thomasjm commented May 28, 2021

I updated the docs so I'm going to close this now, but feel free to let me know if you have any other questions.

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

No branches or pull requests

2 participants