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

[0.29.9] pluck inside pipe get ts error #107

Open
nathan1530 opened this issue Mar 5, 2024 · 2 comments
Open

[0.29.9] pluck inside pipe get ts error #107

nathan1530 opened this issue Mar 5, 2024 · 2 comments

Comments

@nathan1530
Copy link

The error msg:

Argument of type '{ <U extends O[keyof O], UK extends keyof U, O extends Record<string, any>>(obj: "value" extends UK ? O : never): { [OK in keyof O]: O[OK]["value"]; }; <U extends readonly unknown[] | Record<"value", any>>(list: readonly U[]): U extends readonly (infer T)[] ? T[] : U extends Record<...> ? T[] : never; }' is not assignable to parameter of type '(...args: Data[][]) => (number | null)[]'.
  Type '{ [x: string]: any; }' is missing the following properties from type '(number | null)[]': length, pop, push, concat, and 25 more.

image

Here is a minimal repo to reproduce the error
https://codesandbox.io/p/devbox/vm2hyt?file=%2Fsrc%2Findex.ts%3A7%2C22

I am not sure if my type in pipe<...> is wrong but it works in 0.29.4

@Harris-Miller
Copy link
Collaborator

Your R.pipe<> typings is off by a bit: R.pipe<[Data[]], (number | null)[], number[]>(), but that's not the core problem

The problem here is due a combination of two things. First is the fact that typescript always picks the last overload when you pass a function as a prop. And R.reject has this:

export function reject<A, P extends A>(
  pred: (val: A) => val is P,
): {
  <B extends A>(list: readonly B[]): Array<Exclude<B, P>>;
  <B extends A>(dict: Record<string, B>): Record<string, Exclude<B, P>>;
};

R.reject(R.isNil) falls into this and so in your R.pipe, The R.reject is expecting a Record<string, B> and not a B[]. But R.pluck() is now, correctly, returning B[] (#71 fixed that, before it was returning an obj, not an array of objects like it should have, this is why you didn't have the problem before)

Since most use-cases for R.filter and R.reject is to pass a list and not an object, the list overload should come last. That's how it is on map as well. I actually have an open MR for this: #106. I'm going to add to that MR an update for R.reject as well

The second is how the new R.pluck is what I have been calling "the collapsing generics problem". You can read about it all here: #54

The tl;dr is because R.Pluck supports both and object and an array, the generic collapses to unknown, This is specifically due to the fact that there is more than one overload. If you use only one overload, the generic transfers. You can see this in action here: https://tsplay.dev/m3qojw

A short-term fix for you is to not use the curried varieties of those functions, and wrap them with arrow functions in your pipe

const extract = R.pipe<[Data[]], (number | null)[], number[]>(
  x => R.pluck("value", x),
  x => R.reject(R.isNil, x),
);

This is far from ideal, but will get around the typing problem until we can release a fix

@nathan1530
Copy link
Author

Thank you for responding so quickly. I will use the workaround for now.

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

2 participants