typed-typings / npm-ramda

TypeScript's type definitions for Ramda
MIT License
384 stars 64 forks source link

map and Functor #294

Open wclr opened 6 years ago

wclr commented 6 years ago
interface MyFunctor<T> {
  map<U>(project: (t: T) => U): MyFunctor<U>
}

declare const myFunctor: MyFunctor<string>

const result = R.map(() => 1)(myFunctor)

image

result should be MyFunctor<number>

ikatyang commented 6 years ago

We have no ability to get your MyFunctor<T> and preserve MyFunctor then return MyFunctor<U> since we cannot get the signature of MyFunctor itself, it seems to be a TS feature request.

interface Functor<T> {
    map<U>(fn: (x: T) => U): Functor<U>;
}

// current
declare function map<T, U>(fn: (x: T) => U, functor: Functor<T>): Functor<U>;

// what you may want
declare function map<T, U, F extends Functor<T>>(
  fn: (x: T) => U,
  functor: F
): ???;
// ^^^ AFAIK, there's nothing we can put there to get what you want.
wclr commented 6 years ago

I expected something like this to work:

declare function map<T, U>(
  fn: (x: T) => U  
): <FI extends Functor<T>, FO extends Functor<U>>(f: FI) => FO

But it doesn't not. TS is disappointing often.

Also this issue probably relates to this: https://github.com/Microsoft/TypeScript/issues/1213

goodmind commented 6 years ago

@ikatyang probably you can emulate HKT with same thing https://github.com/gcanti/fp-ts does

ikatyang commented 6 years ago

It seems HKT uses the fake ID to match their interface and needs to register the ID on the map signature, which seems hard to apply on npm-ramda since we do the codegen, there's nowhere users can inject their signatures simply.

interface HKT<ID, T> {
  __id: ID;
  __value: T;
}
interface Functor<T> extends HKT<"Functor", T> {
  map<U>(fn: (t: T) => U): HKT<"Functor", U>;
}
interface MyFunctor<T> extends HKT<"MyFunctor", T> {
  map<U>(fn: (t: T) => U): HKT<"MyFunctor", U>;
}

declare function map<T, U>(fn: (x: T) => U, functor: MyFunctor<T>): MyFunctor<U>; // register
declare function map<T, U>(fn: (x: T) => U, functor: Functor<T>): Functor<U>;

declare function length(x: string): number;
declare const functor: Functor<string>;
declare const myFunctor: MyFunctor<string>;

map(length, functor); //=> Functor<number>
map(length, myFunctor); //=> MyFunctor<number>

Microsoft/TypeScript#1213 should be what we need here.

wclr commented 6 years ago

https://medium.com/@gcanti/higher-kinded-types-in-typescript-static-and-fantasy-land-d41c361d0dbe

which seems hard to apply on npm-ramda since we do the codegen,

Hm. I think everything with code gen should be more flexible.