Code Monkey home page Code Monkey logo

npm-ramda's Introduction

types/npm-ramda

Travis Gitter Greenkeeper

TypeScript's type definitions for Ramda

Status

Typing compatible with [email protected] and typescript@~2.9.2 (strictFunctionTypes: false)

Note: many of the functions in Ramda are still hard to properly type in TypeScript, with issues mainly centered around partial application, currying, and composition, especially so in the presence of generics. And yes, those are probably why you'd be using Ramda in the first place, making these issues particularly problematic to type Ramda for TypeScript.

Features

  • support placeholder ( R.__ )
  • support partial import ( import map = require("ramda/src/map") )
  • support selectable overloads ( use 0-param: R.map<"11", "list">() )

Usage

The following command install the types from the dist branch, which is the newest version and contains selectable and placeholder types.

# using npm
npm install --save-dev types/npm-ramda#dist

# using yarn
yarn add --dev types/npm-ramda#dist

# using jspm
jspm install --dev github:types/npm-ramda@dist

# you can also choose which version to install using #<branch/commit/tag>
yarn add --dev types/npm-ramda#dist-simple # contains basic features
yarn add --dev types/npm-ramda#dist-selectable # contains selectable-overloads
yarn add --dev types/npm-ramda#dist-placeholder # contains placeholder

If you load Ramda via a script tag, install with the --global flag instead.

If not using npm/yarn, you may need to add these typings to paths in tsconfig.json:

For the full package:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths" : {
       "ramda": [
         "location-of-types/npm-ramda-package/index"
       ]
     }
  }
}

If using partial imports:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths" : {
       "ramda/src/*": [
         "location-of-types/npm-ramda-package/src/*"
       ]
     }
  }
}

Testing

This project uses dts-jest to test types and values simultaneously, so as to ensure our types are always up to date.

# test
yarn run test

# test with watching mode
yarn run test -- --watch

After you changed some tests/types, you have to run yarn run remap to update the diff-friendly snapshots, and you can see their diff clearly in generated files (./snapshots/*.ts).

(You can also run yarn run remap-watch to use it in watching mode.)

test files:

  • unit tests: ./tests/*.ts (test types)
  • integration tests: ./tests/ramda-tests.ts (test types and values)

Building types

# build types (./templates/*.ts -> ./ramda/dist/**/*.d.ts)
yarn run build

# build types with watching mode
yarn run build-watch

FAQ

Why are the typings here not carbon copies of the ones in the Ramda docs?

  • There are some differences, among which TypeScript's syntax, though the goal differs here as well: while the Ramda docs aim to explain the functions, the goal here is to accurately infer types within TypeScript. Longer version here.

Why does compose not infer well?

  • TypeScript cannot do backward inference as needed for compose (ref). The pipe variants work a bit better than the compose versions.

Contributing

Pull requests are welcome! If you'd like to help out, two good places to start are the issues as well as the tests.

Do note that all of the typings are now being generated (automatically) using the templates.

npm-ramda's People

Contributors

alepop avatar ccapndave avatar dependabot[bot] avatar dumconstantin avatar fatsu avatar gitter-badger avatar greenkeeper[bot] avatar holymeekrob avatar ikatyang avatar iofjuupasli avatar issei-m avatar jcristovao avatar jesseschalken avatar jon49 avatar jonboiser avatar kiaragrouwstra avatar knpwrs avatar laurence-myers avatar liorshalev01 avatar mrdziuban avatar nateabele avatar nshahpazov avatar ntindall avatar paavohuhtala avatar piq9117 avatar rweng avatar sledorze avatar urossmolnik avatar wclr avatar wip0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

npm-ramda's Issues

[RFC] number typing for prop(), propEq() and friends

Hey, I noticed you had a few entries like this:

        // propEq<T>(name: number, val: T, obj: any): boolean;
        propEq<T>(name: string, val: T): (obj: any) => boolean;
        // propEq<T>(name: number, val: T): (obj: any) => boolean;

I use prop() and propEq() for array offsets pretty frequently, so I locally patched them to add number support. Obviously that's not ideal, so I'd be happy to push you a PR if you're interested.

Thanks for investing the time to maintain this.

slice defaults to first returned item with poly

Both of these throw errors in VS 2013 since they default to the previously defined terms.
R.slice(2, 5)(str); //=> 'llo'
R.slice(2)(5, str); //=> 'llo'

Proposed solution:

Create an intermediary interface to deal with this problem (something I have done in my own code); which has the varying types in the interface.

I'll update this when I get time to fix it. Possibly with a pull request.

where typing

@jon49 Following up on PR #7, I came up with the following possible solution:

interface ObjPred2 {
        [index:string]: (x: any, y: any) => boolean;
}
where<ObjPred2,U>(spec: ObjPred2, testObj: U): boolean;

It seems to pass the test, but I haven't poked around to see if it is general enough. What do you think?

Composition and argument order: pipe ok, compose errors

const x = R.cond([
  [R.F, R.F],
  [R.T, R.identity]
]);

const y = R.compose(x, R.inc);

If I use compose or pipe with cond function, there is an compiling error.

Error TS2345: Argument of type 'Function' is not assignable to parameter of type '(x0: {}, x1: {}, x2: {}) => {}'.
Type 'Function' provides no match for the signature '(x0: {}, x1: {}, x2: {}): {}'

at compose/pipe line.

addIndex doesn't play with reduce

Hey,
So, since ramda 0.15 the overall consensus is that indexed functions are removed from ramda, and instead we do R.addIndex(functionToAddIndex).

Unfortunately, this does not play with reduce to generate the reduceIndexed function:

var reduceIndexed = R.addIndex(R.reduce);

Yields:

TS2345: Argument of type '{ <T, TResult>(fn: (acc: TResult, elem: T) => TResult | Reduced<TResult>, acc: TResult, list: T[]...' is not assignable to parameter of type '(f: (item: any) => any (...)

I added this as a quick fix, but I'm pretty sure there might be a more accurate definition:

addIndex<T, U>(fn: (f: (item: T) => U, list: T[]) => U[])
              : CurriedFunction2<(item: T, idx: number, list?: T[]) => U, T[], U[]>;
// I've added this
addIndex<T, U>(fn: (f: (acc:U, item: T) => U, aci, list: T[]) => U[])
              : CurriedFunction3<(acc, item: T, idx: number, list?: T[]) => U, U, T[], U[]>;

What do you think?

Type definition for evolve breaks nested evolution.

The example given in the Ramda documentation illustrates using evolve to modify attributes several degrees deep into a nested structure.

This is no longer possible with the latest type defintion for evolve, since it expects a {[index: string]: function}

I realize it may not have been as well typed, but this worked on a previous version of the type definitions.

limited use of [index:string]

Currently some function definitions like propEq use the index signature to type object arguments. This seems of limited use, because the supplied object needs to have this index signature explicitly defined. For example.
One of the type signatures of propEq is

propEq<T>(name: string, val: T, obj: {[index:string]: T}): boolean;

Using this function with var obj = {a: 1, b: 2} like

propEq('a', 1, obj); // Type error

is correct, however TypeScript complains with:
argument of type 'string' is not assignable to parameter of type 'number' pointing to the a parameter.
This is because obj does not have a index signature. If we add this signature to obj explicitly the type error disappears:

var obj: {[index: string]: number} = {a: 1, b: 2}
propEq('a', 1, obj); // OK

This reason for this behavior is explained in http://stackoverflow.com/questions/22077023/why-cant-i-indirectly-return-an-object-literal-to-satisfy-an-index-signature-re#22077024

I think the requirement that only objects with an index signature can be used is too strict and that we therefore should limit the use of index signature to those cases where it is obviously (but I can not think of one at the moment).

Any thoughts on this issue?

Typing for pipe and compose

pipe/compose are really the main building blocks of Ramda, and it seems that a lot of the time Typescript doesn't correctly figure out the types from what's in the chain and its necessary to explicitly put the type into the generic. Sometimes even this doesn't work and you have to <any> the whole pipeline to get it to compile. This isn't a specific issue as such, and I don't have any particular solutions but I just wanted to put it out there:

What could we do to improve the typing of pipe/compose?

path/prop: also allow number (esp. for navigating arrays)?

Currently, Ramda's path / prop and similar methods are described in their docs as using string paths/props, while in its implementation -- and imho reasonably so esp. when dealing with Arrays -- also allows numbers:

R.path([0, 'a'], [{ a: 1 }])
// 1
R.path(['0', 'a'], [{ a: 1 }])
// 1
R.prop(0, ['a'])
// "a"
R.prop(0, { '0': 'a' })
// "a"

Now, I would like for the typings to also allow me to use these functions how I was already using them. You may counter this would clash with Ramda's docs, and therefore possibly intention. So I guess the question here is, would you consider this a bug in Ramda's implementation, or should we request they adjust their docs and accordingly allow this in the typings?

Definitely-Typed depreciation

First off, thank you for these fantastic typings and happy to see that there is recent activity on this.

Because my team moved off of definitely typed on on to the newer typings I created a copy of these typings at https://github.com/enriched/typed-ramda that I could hack on. I have added/corrected some functionality there as well, just on an as needed basis.

I am wondering if you want to combine efforts on this somehow though. I don't know if we can have both the ambient and typings definitions in the same place, but I definitely don't want to be missing out on your fixes or vice-versa.

Issue with find: doesn't flow

type Task = {id: number}
let tasks: Task[] = []
R.find(task => task.id === 1, tasks) // this works

R.find(task => task.id === 1)(tasks) // this doesn't work works

Is it possible to make it flow in second case?

flatten

Basic test fails to infer: let numbers: number[] = R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]);

Error on lens composition

const sectioneditems = {sections: [
  {items: []},
  {items: []}
]}
const elem = "Hello"
R.over(R.compose(R.lensProp("sections"), R.lensIndex(secitems.sections.length - 1), R.lensProp("items")), R.append(elem), sectioneditems)

This throws an error:

Argument of type '(x: any) => any' is not assignable to parameter of type 'Lens'

The code runs fine but typescript throws an error.

I installed this with typings install npm~ramda

Type argument for type parameter 'TResult' cannot be inferred

Hey @donnut, thanks for doing these definitions. I have a question that might have a simple answer. I can't figure out how to make a legal use of R.reduce:

/// <reference path="typings/ramda/ramda.d.ts"/>

import R = require('ramda');

var add = (item: number, sum: number): number => sum + item

var avg = (list: Array<number>): any => {
  var sum: number = R.reduce(add, list);
  return sum / list.length;
}

error TS2453: The type argument for type parameter 'TResult' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
  Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate 'number[]'.

Upgrade to ReadOnlyArray (TS 2.0)

In TypeScript 2.0 we have ReadOnlyArray which I think is a perfact match for a library like ramda that does not do any mutations.

Would it be OK if I did a PR that changes to ReadOnlyArray?

Here is a short example how it works:

let a: Array<number> = [0, 1, 2, 3, 4];
let b: ReadonlyArray<number> = a;
b[5] = 5;      // Error, elements are read-only
b.push(5);     // Error, no push method (because it mutates array)
b.length = 3;  // Error, length is read-only
a = b;         // Error, mutating methods are missing

Change/Addition of extra type parameters to some functions?

I'm primarily referring to R.propEq() in my situation, but this probably applies elsewhere. There are two parts to my question/issue.

First, in propEq, currently the type parameter <T> is on the val parameter, which I don't personally find very useful. (Maybe I'm missing something.) I think it would be much more useful for <T> to be the type of obj, as I find that plays better with partial application:

// Current definition: propEq<T>(name: string, val: T): (obj: any) => boolean;
let findMatching1 = R.filter(R.propEq('id', 1)); // Return type is any[] -> any[]

// Suggested definition: propEq<T>(name: string, val: any): (obj: T) => boolean;
let findMatching2 = R.filter(R.propEq<User>('id', 1)); // Return type is User[] -> User[]

Second: It looks like TS (at least as of 1.8.10) can support having multiple definitions, identical except for their generic types. The following seems to work fine:

propEq(name: string, val: any): (obj: any) => boolean;
propEq<T>(name: string, val: any): (obj: T) => boolean;

Having both definitions allows you to do either of the examples in my code above, depending on your scenario.

What do you think? Of course, this is particular situation relies on my belief that the type of val is not useful. We could add additional type parameters <T, U> for both val and obj but we could start to see a sort of exponential explosion of near-identical definitions. (And it does break backwards compatibility, I know.)

properly handle currying

Earlier mentioned here.

We've been using CurriedFunction interfaces, and the current approach had kind of been to, e.g. for an arity-4 function, do the type definition at least 4 times:

  • (a,b,c,d) => Res
  • (a,b,c): (d) => Res
  • (a,b): CurriedFunction2<c,d,Res>
  • (a): CurriedFunction3<b,c,d,Res>
    ... simplifying for brevity.
    In case there would be two distinct definitions for a function (e.g. string and array versions), this would further multiply.

This is a bit of a pain point currently, and I hope we could just do one definition in a single CurriedFunction4 definition for cases like that, although currently it appeared parameterized functions (-> using generics) failed to parse for me that way.

Moreover, TypeScript also does not seem to like the idea of having regular 'function' versions side-by-side as well (needed if definitions using generics have to go the traditional route), while I suppose this curried route would currently also lose parameter names (hopefully improved on in the WIP variadic kinds?).

Question: `compose` and `assoc` to build a structure

Hi folks, this is a question rather than an issue. I'm somewhat new to the wonders of ramda and TypeScript and I might have a naive question here, so please bear with me 😉

I'm trying to build an object that matches a given interface through compose and mutliple assocs, something like

interface SomeStruct {
  a: number[];
  b: string[];
  c: { [index: string]: string };
}

const x: SomeStruct = {
  'a': [],
  'b': [],
  'c': {},
};

const fun = (y: SomeStruct): SomeStruct => {
  return compose(
    assoc('a', [1, 2, 3]),
    assoc('b', ['a', 'b', 'c']),
    assoc('c', { 'k': 'v'})
  )(y);
};

fun(x);

Doing this, I'm getting a following error:

error TS2322: Type '{ prop: number[]; } & {}' is not assignable to type 'SomeStruct'.
Property 'a' is missing in type '{ prop: number[]; } & {}'

The effective and intermediate structure of x matches the SomeType at all steps of this function application. Is there some way around it besides using as any after compose? Am I missing something pretty basic here?


Edit: Sorry, now I see it might be related to #90

Test for `R.props` fails at `fullName`

Error:
Argument of type '{ [x: number]: undefined; last: string; age: number; first: string; }' is not assignable to parameter of type 'any[]'.
Property 'length' is missing in type '{ [x: number]: undefined; last: string; age: number; first: string; }'.
C:\r\mobiledlr\mobiledlr\typings\ramda\ramda-tests.ts   1119    14  ramda-tests.ts

When I have time, I'll think about this one.

better typing for toPairs, tentative.

toPairs is currently defined as:

toPairs<F,S>(obj: {[k: string]: S} | {[k: number]: S} | any): [F,S][];

this results in the following inference:

const a1 = R.toPairs({1:true})                    // type inferred: [{}, {}][]
const a2 = R.toPairs({"1":true})                  // type inferred: [{}, {}][]
const a3 = R.toPairs<string,boolean>({"1":true})  // type inferred: [string, boolean][]

If you change the toPairs signature to:

toPairs<V>(obj : {[k : string] : V}) : [string,V][];

then the types inferred will be:

const b1 = R.toPairs({1:true})             // type inferred: [string, boolean][]
const b2 = R.toPairs({"1":true})           // type inferred: [string, boolean][]
const b3 = R.toPairs<boolean>({"1":true})  // type inferred: [string, boolean][]

I don't know if this new signature is really valid, because:

  1. Why is the any type included in the original signature? Using something non-object like with toPairs seems like an error you want to trap at compile time.
  2. Why is {[k:number] : S} included in the original signature? Given in javascript keys are always converted to strings. Note the original toPairs always returns keys as string's, including the case when the argument is an array.

Obscure definition problem

This code is ok, but does not compile

let filterMatrix = function (v: number, m: Array<Array<number>>): Array<number> {
  return chain(filter((c) => c == v), m)
}

let b = [
  [0, 1],
  [1, 0]
]

console.log(filterMatrix(1, b)) // --> [1, 1]

I'm getting this

TSError: ⨯ Unable to compile TypeScript
src/board.ts (11,10): Type '{}[]' is not assignable to type 'number[]'.
  Type '{}' is not assignable to type 'number'.

Too much of "any"

Don't you think that there are too much of "any" type used through out the definitions, or maybe I am missing something.
Consider for example these definitions:

pair(fst: any, snd: any): any[];
insert(index: number, elt: any, list: any[]): any[];
assoc(prop: string, val: any, obj: any): any;
clone(value: any): any;
// there are probably more, these are just found by a quick look

While we still can have them for the cases we don't have a strict definitions for input/output, I still believe that main point is to squeeze out as much of type safety as we can from Typescript.
So don't you think we should have a generically typed definitions as much as possible for every function?
For above examples it might look like this:

pair<F, S>(fst: F, snd: S): [F, S];
insert<T>(index: number, elt: T, list: T[]): T[];
assoc<T>(prop: string, val: any, obj: T): T;
clone<T>(value: T): T;

What do you think?

R.merge and type intersection

Hi, I'm having problems with R.merge(a,b) where b is a subset of a:

interface Person {
  first: string,
  last: string
};
function setLast(last: string, person: Person) : Person {
  return R.merge(person, { last });
}

The code above complains with:

error TS2322: Type '<T1>(a: T1) => T1 & { last: string; }' is not assignable to type 'Person'.
  Property 'first' is missing in type '<T1>(a: T1) => T1 & { last: string; }'.

If I explicitly state T1 and T2, the code works but it gets very ugly:

function setLast(last: string, person: Person) : Person {
  return R.merge<Person, { last:string }>(person, { last });
}

Most of the time I use R.merge to update existing properties of immutable objects (like last in the example above). I think support for this use-case should be straight-forward. Worst case, this might be OKish:

R.merge<Person>(person, { last }) : Person & { last:string } // == Person

Having to specify the type of { last } feels like an unnecessary pain.

On a side note, for the use-case when I'm augmenting a type (i.e. A & B != A) I have no problem defining the new type.

R.__ missing

Hey,

The definition for R.__ (http://ramdajs.com/docs/#__) is missing, is this intentional?

I've tried merging the Static interface with a local definition but it doesn't want to play nice :(

declare namespace R {
    interface Static {
        __(): any;
    }
}

Update 1

After some more adventures I'm not sure what the type should be either. I modified the index.d.ts in my node_modules/@types/ramda to include __ like the following:

interface Static {
        __(): any;
        ...

But I then couldn't do R.gt(R.__, 0) as R.gt is (a: number, b:number) => boolean.

This lead to me just defining R.__ as just any (not a function at all) in the interface.

Update 2

const R__ = (R as any).__ works.

error with immutablejs data structures.

First of all, thank you for typescript-ramda.

I'm using immutablejs and it gives me this error when I use a List or Map in the second paramater of filter
example:

const num = List([1, 2, 3, 4, 5]);
const filtered = R.filter(x => x === 5, num);

I get this:
Argument of type 'List<number>' is not assignable to parameter of type 'any[]'.

So, I went into the types and changed this line

filter<T>(fn: (value: T) => boolean, list: T[]): T[];

to

filter<T>(fn: (value: T) => boolean, list: Functor<T>): Functor <T>;

It worked after I changed it, it also worked on Map
example:

const numMap = List([Map({
  num1: 1,
  num2: 2,
  num3: 3
})]);
const filteredMap = R.map((x: Map<any, any>) => R.filter(y => y === 1, x), numMap);

Is this the right step? what are the repercussions of this modification? Should I submit a PR?

Move to @types

Hi @donnut. Wanted to open this up for feedback from you, but would be interested in moving this repo into @types with the rest of the projects? I'd love to help out on this definition where possible and I'm happy to add you to that organisation, if you'd like (with or without moving this repo).

Variants of R.map() and lost types

For the partial applied variants of R.map() the TypeScript compiler fails to infer/resolve the types of the parameter, e. g. elem in the code example below.

import * as R from "ramda"

const array = [1, 2]
R.map(elem => elem, array) // (parameter) elem: number
R.map(elem => elem)(array) // (parameter) elem: {}

Here are the type declarations from @types/ramda:

map<T, U>(fn: (x: T) => U, list: T[]): U[];
map<T, U>(fn: (x: T) => U, obj: Functor<T>): Functor<U>; // used in functors
map<T, U>(fn: (x: T) => U): (list: T[]) => U[];

I quickly tried the declarations from the master branch. But they also didn't work.

I guess there are some issues in this repository related to this problem. I also wonder, if there is an issue on Microsoft/TypeScript related to this.

Map definition is overly restrictive.

R.map(parseInt,{a:'1',b:'2'});

Is not accepted.
Are we supposed to declare a Functor for each object we intend to map over?
This is clearly not practical at all.

Preferable to have:

map<T, U>(fn: (x: T) => U, obj: any): any;

What do you think?

Composition and generics

This errors:

R.compose(R.fromPairs)([['1','A'], ['2','B'], ['3','C']])
[ts] Argument of type '[string, string][]' is not assignable to parameter of type 'KeyValuePair<number, any>[]'.
  Type '[string, string]' is not assignable to type 'KeyValuePair<number, any>'.
    Types of property '0' are incompatible.
      Type 'string' is not assignable to type 'number'.

Though this works as it should (without compose and with numbered index)

R.fromPairs([['1','A'], ['2','B'], ['3','C']])

R.compose(R.fromPairs)([[1,'A'], [2,'B'], [3,'C']])

R.invoker signature

R.invoker signature take the first parameter as a arity: Number -> String -> (a -> b -> ... -> n -> Object -> *)

However, @types/ramda signature take the first parameter as the function name.

Is this a versioning problem?

Regards,
Lior,

Installing as a global module fails

I get the following error when trying to install with the global option as per the README. I also tried dt~ramda and it gave the same error. I found that #50 changed the typings to an external module format. Do we need to do something different to support both external module format and global?

$ typings install ramda --save --global

typings ERR! message Attempted to compile "ramda" as a global module, but it looks like an external module. You'll need to remove the global option to continue.

typings ERR! cwd <path>
typings ERR! system Darwin 15.6.0
typings ERR! command "/usr/local/bin/node" "/usr/local/bin/typings" "install" "dt~ramda" "--save" "--global"
typings ERR! node -v v5.10.1
typings ERR! typings -v 1.3.3

Errors on curried R.match

image
I believe need to add signature

/**
         * Tests a regular expression agains a String
         */
        match(regexp: RegExp, str: string): any[];
        match(regexp: RegExp): (str: string) => any[];

Generics lost on currying

Also see: #73

This (correct) function does not compile

import * as R from "ramda"
import {curry} from "ramda"

let updateBy = curry((pred, val, array) => {
  let i = R.findIndex(pred, array);
  if (i >= 0) {
    return R.update(i, val, array);
  } else {
    return array;
  }
})
Argument of type '{}' is not assignable to parameter of type '(a: {}) => boolean'.
  Type '{}' provides no match for the signature '(a: {}): boolean' (2345)
    at getOutput (/usr/local/lib/node_modules/ts-node/src/index.ts:280:15)
    at compile (/usr/local/lib/node_modules/ts-node/src/index.ts:289:14)
    at loader (/usr/local/lib/node_modules/ts-node/src/index.ts:304:23)
    at Object.require.extensions.(anonymous function) [as .ts] (/usr/local/lib/node_modules/ts-node/src/index.ts:321:14)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Function.Module.runMain (module.js:575:10)
    at Object.<anonymous> (/usr/local/lib/node_modules/ts-node/src/_bin.ts:172:12)
    at Module._compile (module.js:541:32)

Generic types with currying

I'm not sure if it is considered bad practice, but I'm attempting to use curry with a function dependent on a generic type. In the example below, how would I declare that the second type argument to R.CurriedFunction2 is the generic type T rather than an Object literal?

export type hasKey = R.CurriedFunction2<string, {}, boolean>;
export const hasKey: hasKey = curry(<T>(key: string, someObject: T): boolean => key in someObject);

If this isn't an issue per say of the type system for Ramda in TypeScript, feel free to close this.

Partially applied sortBy fails in compose chains

Example:

const nums = [ 3, 2, 1 ];

const res:number[] = R.compose(
  R.sortBy<number>(n => n.toString()),
  R.filter((n:number) => n > 1)
)(nums);

Before, this worked because sortBy was:

  sortBy<T>(fn: (a: any) => string): (list: T[]) => T[];

But now sortBy is:

sortBy(fn: (a: any) => string): <T>(list: T[]) => T[];

so we cannot specify <T> anymore (and the callback always defaults to {}):

const res:number[] = R.compose(  // < Type '{}[]' is not assignable to type 'number[]'
  R.sortBy(n => n.toString()),
  R.filter((n:number) => n > 1)
)(nums);

Shouldn't sortBy be defined as:

  sortBy<T>(fn: (a: T) => string): (list: T[]) => T[]; // note the typed fn!

(also this would allow type inference using the type of fn's argument similarly to filter)

This pattern of returning generic functions from partial application is also present in other functions so I recommend checking those functions as well as they might be failing in a similar fashion.

Running this might help you identify them:

 grep '\w(.*<' ramda.d.ts

(current count for me is 37).

typings and tsd

How far are these type definitions from being published to DefinitelyTyped?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.