typescript typings
Hello Is there in plans to add typescript bindings to "folktale" ?
Unlikely for now, the type system implemented by TypeScript (and Flow) are not expressive enough to support most of the constructs that Folktale uses, so you'd just end up with a lot of any types, which is not very useful. Folktale was not written for a particular type system, which makes this a bit difficult too (as the features require many advanced type system techniques).
Depending on how Flow and TypeScript advance in the future I might look into this again, though.
Right now Folktale requires at the very least three type system features:
-
Parametric polymorphism, the ability of writing a generic type over some parameters, and then specialising that later.
Maybe<a>,Either<a, b>, etc. all require this. Both Flow and TypeScript support this (some people refer to them as "generics"); -
Higher-Kinded polymorphism, the ability of writing a generic type that you can pass around, and yield new types. Imagine the above, but
Maybeis just as valid a usage asMaybe<a>, it just results in a "type function" where the thing you're passing the type to is supposed to provide the argument forMaybeto construct a type. This is required for monads and applicatives. The type of.applyis:apply :: forall a, b, c. (Applicative a) => (this: a<b → c>, a<b>) → a<c>The
(Applicative a) =>part just says "the type variableais constrained to be an Applicative". Since we're using an object-oriented language we could just specialise this instead:apply :: forall b, c. (this: Maybe<b → c>, Maybe<b>) → Maybe<c>But this still requires you to be able to write
Maybe<b → c>as the type ofthis, which is not possible in TypeScript afaik. Flow might get higher-kinded polymorphism at some point (https://github.com/facebook/flow/issues/30) but it's not one of their priorities. -
first-class tags (or some other kind of tagging/sums), basically the ability of overloading a method based on a static value, which is used by things like
.matchWith, which call a function based on the tag an object has. Flow has had something like this since forever, TypeScript added this recently.
Some features use reflection or generate values. These could only be typed if we had a type system with dependent types (that is, your types are basically functions, so you can write things like sort : (Vector(len, x), (x, x -> Ord)) -> inTime(nlogn, Sorted(Vector(len, x))), which statically verifies that you've implemented a correct sort function that runs in n log n). Dependent types are still not practical.
Thanks for a great answer @robotlolita , I’ve been wondering the same thing as @djleonskennedy for a while, it’s good to have a complete explanation about this.
Understood thank you @robotlolita
Also have addition, even any typings would be handful, because now we can't use library with TS at all :(
I agree with @djleonskennedy
@djleonskennedy doesn't TypeScript infer any from things you haven't declared a type for, and then propagates that?
@robotlolita if implicit any flag is on, than we need typing's anyway :(
Mmh, I'll look into this over the weekend.
@robotlolita thank you
It's fine to use with typescript I'm just applying a band aid fix for now by declaring the module with any type just so I can use it with typescript.
declare module 'data.maybe' {
const Maybe: any;
export = Maybe;
}
@piq9117 thank you i use it now in this way
I hacked together some typings for use with the data.validation and data.maybe modules. The types should probably describe the underlying concepts such as Functor, Monad, but they are just hardcoded for now:
declare module 'data.maybe' {
import Validation from 'data.validation';
const Maybe: {
fromValidation: <Success, Failure>(validation: Validation<Success, Failure>) => Maybe<Success>
fromNullable: <T>(nullable: T | undefined | null) => Maybe<T>
Just: <T>(t: T) => Maybe<T>
of: <T>(t: T) => Maybe<T>
Nothing: () => Maybe<never>
}
type Maybe<T> = {
value: T
getOrElse: (fallback: T) => T
map: <T2>(fn: (t: T) => T2) => Maybe<T2>
chain: <T2>(fn: (t: T) => Maybe<T2>) => Maybe<T2>
}
export default Maybe
}
// Applicative
declare module 'data.validation' {
const Validation: {
Success: <Success>(success: Success) => Validation<Success, never>
of: <Success>(success: Success) => Validation<Success, never>
Failure: <Failure>(failure: Failure) => Validation<never, Failure>
}
type Validation<Success, Failure> = {
getOrElse: (fallback: Success) => Success
map: <Success2>(fn: (success: Success) => Success2) => Validation<Success2, Failure>
ap: (validation: Validation<any, any>) => Validation<any, any>
cata: <T>(obj: {
Success: (success: Success) => T,
Failure: (failure: Failure) => T
}) => T
}
export default Validation
}
I'm very much making it up as a go along. I've had to type Validation.ap as returning Validation<any,any>—would love help to fix this.
Also, looking around for a good FP library with support for TypeScript and Fantasy Land, I don't think there's any really strong contenders at the moment. I would love to see Folktale emerge and fill this niche :-)
@OliverJAsh With https://github.com/Microsoft/TypeScript/pull/6739 you can probably write:
type Validation<S, F> = {
ap: <S2>(this: Validation<Function<S, S2>, F>, validation: Validation<S, F>) => Validation<S2, F>
}
But I haven't tried it yet. I don't know if it's on the current TS version either.
Oh, wow! Thanks @robotlolita
@robotlolita That change is included in TS 2.3 which is currently out as a release candidate (RC): https://github.com/Microsoft/TypeScript/releases/tag/v2.3.0
Also, looking around for a good FP library with support for TypeScript and Fantasy Land, I don't think there's any really strong contenders at the moment. I would love to see Folktale emerge and fill this niche :-)
@OliverJAsh check out https://github.com/gcanti/fp-ts for ADT in TypeScript if you haven't already – the project seem to be moving fast.