reduxjs / reselect

Selector library for Redux
MIT License
19.04k stars 670 forks source link

createSelector signature with additional parameters doesn't preserve names #586

Open NordlingDev opened 2 years ago

NordlingDev commented 2 years ago

The inferred type of a selector instance doesn't preserve the extra parameters' names. Instead they are called params_0, params_1, etc... See example below:

type Item = {
  id: string;
  name: string;
};

type State = {
  items: Record<string, Item>;
};

export const selectItemById = createSelector(
  (state: State, itemId: string) => state.items[itemId] || null,
  (item) => item,
);

The inferred type signature of this selector becomes:

const selectItemById: (state: State, params_0: string) => Item | null

As you can see, parameter itemId is now called params_0. From a consumer perspective, this parameter is ambiguous and impossible to understand. How can this be fixed? I honestly don't think I'm doing anything wrong here.

Version: 4.1.6

markerikson commented 2 years ago

There's a couple things that make this difficult.

One is that we have to do some extremely complex type transformations to figure out "the tightest possible acceptable combination of parameters from all input functions".

Another is, what would happen if you had multiple input functions, with the same listed arguments, but you gave them different names? What name should get used for the result?

It might hypothetically be possible to do something that preserves the names - I'm honestly not sure.

But given how complex the types are, this is going to be extremely low priority for us to look at, and I generally doubt that there's a solution that can preserve the names well.

NordlingDev commented 2 years ago

@markerikson I'm not too familiar or experienced with the implementation, but if the incoming parameters were instead provided by one single explicitly typed object, then there is no point to preserve the names as they're declared in the object.

const selectItemById: (state: State, params_0: { itemId: string }) => Item | null

I will have to try this one out. Perhaps there is nothing more to it than this.