ramda/types

ramda pick type inference is not correct

Closed this issue · 1 comments

In this release the types of pick were changed to make it more strict so that it only accepts names of keys defined in the object. However this does not work when an object defines a list of generic properties e.g. [key: string]: string

In addition, the description of the pick function is not in line with the new types.
Returns a partial copy of an object containing only the keys specified. If the key does not exist, the property is ignored.

Specifically the part If the key does not exist, the property is ignored. does not hold as far as I can see.

However this does not work when an object defines a list of generic properties e.g. [key: string]: string

That is the expected behavior. When you have a type Record<string, string> or { [key: string]: string }, that is saying "the key is any string", so the function pick() accepts any string. It cannot determine the keys you add to it at runtime

In addition, the description of the pick function is not in line with the new types.
Returns a partial copy of an object containing only the keys specified. If the key does not exist, the property is ignored.

Specifically the part If the key does not exist, the property is ignored. does not hold as far as I can see.

This describes the runtime behavior. For typescript, we look at the keys and error if they do not exist as a type-safety. If you use the built-in Pick<> helper type, it works the same way

I suspect your issue might be because you're not on typescript@5 yet. Both pick and omit are defined using the const modifier in the type definitions which tells typescript to read the array literal "as const", since that modifier is not supported in typescript@4, we have a separate version that removes that keyword. What this means is you won't always get the desired behavior with using as const on your input keys array

// In typescriipt@4, This won't always work:
const r = pick(['foo', 'bar'], {} as Record<string, number>);

// you need to
const r = pick(['foo', 'bar'] as const, {} as Record<string, number>);