Definitelytyped: @types/ramda - Special placeholder __ (double underscore) is not defined

Created on 17 Apr 2018  路  7Comments  路  Source: DefinitelyTyped/DefinitelyTyped

Authors: @donnut @mdekrey @mrdziuban @sbking @afharo @teves-castro @1M0reBug @hojberg @charlespwd @samsonkeung @angeloocana @raynerd @googol @moshensky @ethanresnick @leighman @CaptJakk

Hi. I'm trying to import the special placeholder __ and as far as I'm seeing there's no definition for it, thus it's returning an error at the import.

Most helpful comment

Thank you guys for posting here.

And @andys8 is right, that's what is happening. Since we don't have any typing definitions at all, the compiler is just saying that it doesn't exist. So I believe yes we should define it as any and improve it later if possible with the new TypeScript's conditional types addon.

All 7 comments

It looks like the issue is that definition fundamentally doesn't exist. So we will have to add it. The tricky part is this: __ needs to inhabit the union of possible values that can be passed to the functions in ramda. The first implementation that jumps out as me is to type it as any. My gut says this is OK, but I would like someone else to chime in here.

Option 1: If we type it as any we consequently cannot extract any type information from it's use, which in some cases can lead to bad type inference.

Option 2: If we type it as what it is (a placeholder) then we'd have to augment every type definition in the rest of the library and will consequently lose accuracy on the type definitions as we won't be able to make return types dependent on the argument types. This may be solvable with conditional types in typescript 2.8

Until we are ready to bump versions to 2.8 (which just was released so it might be a bit), I don't think we can do better than typing it as any for the moment. That said, I believe if any value actually implemented the spirit of any, the argument hole is probably the best candidate.

I think it hasn't been defined because it has been impossible to type it properly. Using the placeholder in a function call changes the type of that function, which is not an easy thing to achieve.
If a solution is possible with conditional types, then that's super cool. Otherwise I'd rather leave it out than have it typed as any.

The recommended workaround is using an arrow function and explicitly passing the parameter.

@googol Isn't any the accurate description of "we can't specify the type". Not having it defined at all, leads to the typescript compiler telling the user it doesn't exist, and this is not true.

Thank you guys for posting here.

And @andys8 is right, that's what is happening. Since we don't have any typing definitions at all, the compiler is just saying that it doesn't exist. So I believe yes we should define it as any and improve it later if possible with the new TypeScript's conditional types addon.

I absolutely think it should be any since that is what it is.

Even if you could import R.__ in typescript, you couldn't use it properly.
Looking at the documentation for R.__ already the second listed example case would fail in typescript.

Assuming g returns a number:

// You can try this out if you monkey patch `__: any;` into the Static interface in your ramda typings in some project
const g = R.curry((a: number, b: number, c: number): number => a + b + c);
const noncurried = g(1, 2, 3);
const curried1 = g(1, 2)(3);
// All good so far

g(R.__, 2, 3)(1) // TSC error: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
// This is because
const tsGetsTypeWrong: number = g(R.__ /* : any */, 2 /* : number */, 3 /* number */);

// When the placeholder is used, the type should become (a: number) => number
const correctTypeWontCompile: (a: number) => number = g(R.__, 2, 3); // Will fail with the R.__: any definition

// Workaround for now 
const workaround = (a: number): number) => g(a, 2, 3); // not quite as beautiful but gets the job done and doesn't result in any confusion

So really what this is about is making the CurriedFunction types react to the presence of the placeholder to change the type they result in. This definitely needs conditional types.

For R.__ a kind of fake nominal type could be used, which could be picked up by the conditional type on the curried type, but without the interaction with the curried functions, R.__ is useless at best, and harmful because of confusion at worst.

@rdsedmundo @googol @andys8: typing R.__ as any is pretty counter-productive. Whereas for anything else it might work, ignoring __ will make type checks fail as it alters function arity, shifting all subsequent parameters as well.

I'd suggest trying the types at npm-ramda, which used codegen to tackle option 2 mentioned by @CaptJakk. If that sounds like a massive undertaking, go thank @ikatyang.

Was this page helpful?
0 / 5 - 0 ratings