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

Why type inference works well when using ramda with ts #3289

Open
Inhye-Cheong opened this issue Jul 19, 2022 · 4 comments
Open

Why type inference works well when using ramda with ts #3289

Inhye-Cheong opened this issue Jul 19, 2022 · 4 comments

Comments

@Inhye-Cheong
Copy link

Inhye-Cheong commented Jul 19, 2022

Hello. I am a front-end developer who enjoys using ramda(+ @types/ramda) + typescript. When using ramda, the type inference of typescript is often much better than using js built-in functions. ex) Object.keys etc.

So, suddenly, a question arose. Can you explain why type inference works so well with ramda? FYI, I'm not a user who knows even the deep stuff of fp-ts, monad, functor, etc.

@Inhye-Cheong Inhye-Cheong changed the title Why type inference works well when using ramda when using typescript Why type inference works well when using ramda with ts Jul 19, 2022
@CrossEye
Copy link
Member

Mostly we hear complaints about that, and have to point them to the DefinitelyTyped folks who maintain the TS typings.

So by the same token, all credit must go to them.

There is an effort underway to move them in-house, but it's not moving quickly.

@Inhye-Cheong
Copy link
Author

Inhye-Cheong commented Jul 20, 2022

@CrossEye

First of all, thanks for the reply.

I'm not using ramda heavily, so I didn't have any "complaints" about type inference as you described.

My question was, How does ramda do better type inference than js built-in functions?

For example,

import * as R from 'ramda';

const MOCK_DATA = {
  'first-key': 'this is first value',
  'second-key': 'this is second value',
}

// using ramda : The type inference of the `key` is correct.
const findKeyUsingRamda = (label: string) => R.keys(MOCK_DATA).find((key) => MOCK_DATA[key] === label);
// using js built-in functions : The type of `key` cannot be inferred.
const findKey = (label: string) => Object.keys(MOCK_DATA).find((key) => MOCK_DATA[key] === label);
                                                                        ~~~~~~~~~~~~~~ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ 'first-key': string; 'second-key': string; }'.
  No index signature with a parameter of type 'string' was found on type '{ 'first-key': string; 'second-key': string; }'.ts(7053)

@CrossEye
Copy link
Member

I know very little about TS typings, nor how these were implemented in DefinitelyTyped for Ramda. But if I were to hazard a guess, then I would expect that the type assigned to R.keys is something like "a function from an Object to an array of Strings" and the one assigned to Object .keys is more like "a function from an Object to a mixed array of Strings and Symbols."

I'm sure this can be looked up, and while I know I could find the Ramda version, I don't know where to look for the Object.prototype one.

Of course that more generic one should also apply to Ramda's keys as well, but I'm guessing the TS implementers took some signals from Ramda's Hindley-Milner-inspired types, and treat some of the signatures as more aspirational than pedantic.

@lisumio
Copy link

lisumio commented Aug 16, 2022

The main difference is that Ramda leverages a combination of generics and keyof operator while native Object.prototype.keys always returns array of strings.

@CrossEye

"a function from an Object to an array of Strings"

Looking at the implementation it goes even one step further - "a function from an Object to an array of Object keys" - which means that it returns a union containing each key:

export function keys<T extends object>(x: T): Array<keyof T>;

While Object.prototype.keys:

keys(o: object): string[];

Because Object.prototype.keys returns array of any strings TS can't determine what type is MOCK_DATA[key] going to be - while when called using Ramda it can guarantee that key will be a key of MOCK_DATA and therefore assume its type.

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

3 participants