在 TypeScript 中使用 createSelector 创建一个选择器工厂

Creating a selector factory with createSelector in TypeScript

像这样创建选择器:

import { createSelector } from 'reselect';

export interface Node {
  nodeId: number
  nodeName: string
}

export type NodeState = {
  nodes: Node[];
  text: string;
};

const nodeListState = (state) => state.nodeList;


const byKey = (key: keyof NodeState) => createSelector(
  nodeListState, (nodeList: NodeState) => nodeList[key],
);

export const getNodes = byKey('nodes');
export const getText = byKey('text');

在其他地方,使用选择器:

import { useSelector } from 'react-redux';

const nodes = useSelector(selectors.getNodes);

nodes.map(...)

这会导致错误:

Property 'map' does not exist on type 'string | Node[]'.
  Property 'map' does not exist on type 'string'.  TS2339

变量节点实际上是一个数组。我这样做是不是错了?在 TS 中设置按键创建选择器的函数的正确方法是什么?

这里发生的事情是 typescript 无法区分 byKey('nodes')byKey('text')。它们 return 是同一类型,即选择文本 string 或节点 Node[] 的选择器。因此 const nodes = useSelector(selectors.getNodes) return 联合 string | Node[] 并且你得到一个错误 string 不是一个数组。

解决此问题的一种方法是放弃 byKey 并分别创建两个选择器。

但是我们可以使 byKey 正常工作,方法是使它成为一个通用函数,该函数取决于调用它时使用的特定键。这样我们就知道 byKey('nodes') 选择了 'nodes' 属性.

如果您对 nodeListState 应用正确的类型,您实际上不需要将第二个选择器的参数指定为 nodeList: NodeState,因为它可以根据 return 推断出来第一个选择器的类型。

const nodeListState = (state: {nodeList: NodeState}) => state.nodeList;

const byKey = <K extends keyof NodeState>(key: K) => createSelector(
  nodeListState, 
  (nodeList) => nodeList[key],
);

现在 getNodes 选择 Node[]getText 选择 string