返回此数组的泛型类型的类型提示数组

Posted

技术标签:

【中文标题】返回此数组的泛型类型的类型提示数组【英文标题】:Typehinting array of generic types that return this array 【发布时间】:2021-02-17 00:55:04 【问题描述】:

我有一个方法useActions,它接受一个函数数组并返回一个绑定动作数组,基本上像:

function useActions<A>(
  actions: Array<ActionCreator<A> | ActionCreatorWithoutPayload>
): Array<ActionCreator<A> | ActionCreatorWithoutPayload> 
  const dispatch = useDispatch()
  return useMemo(() => 
    return actions.map((a) => bindActionCreators(a, dispatch))
  , [actions, dispatch])

用法是这样的:

const [doFoo, doBar] = useActions([actions.doFoo, actions.doBar])

现在的问题是,doFoo 和 doBar 需要完全相同类型的参数。我设法通过编写额外的重载类型提示来解决这个问题:

function useActions<A extends ActionCreator<any>>(actions: [A]): [A]
function useActions<A extends ActionCreator<any>, B extends ActionCreator<any>>(actions: [A, B]): [A, B]
function useActions<A extends ActionCreator<any>, B extends ActionCreator<any>, C extends ActionCreator<any>>(
  actions: [A, B, C]
): [A, B, C]

但这感觉很麻烦。是否有能够支持 n 个参数的通用方法?

【问题讨论】:

如果你改用命名属性会更容易,即。 const doFoo, doBar = useActions(actions)。那是破坏交易吗?我认为可以通过元组映射来完成,但我更擅长对象映射! 【参考方案1】:

使用数组

绑定一个动作创建者根本不会改变它的签名。它仍然需要一个有效负载并返回一个动作。这让生活变得轻松,因为我们不需要映射任何类型。我们只需要返回提供的相同元组。我们没有让useActions 上的泛型引用特定的动作类型,而是让它引用整个元组。然后我们只返回相同的类型。

function useActions<A extends Array<ActionCreator<any> | ActionCreatorWithoutPayload>>(
  actions: A
): A 

但是现在由于actions.map,我们在钩子的主体内部有一个错误,因为array.map 的类型不考虑我们的数组元素是不同类型的,并且会将它们组合在一起。我们通过在 useMemo 调用之后添加 as A 来抑制这种情况,以将类型细化回我们知道的应该是什么。

function useActions<A extends Array<ActionCreator<any> | ActionCreatorWithoutPayload>>(
    actions: A
): A 
    const dispatch = useDispatch()
    return useMemo(() => 
        return actions.map((a) => bindActionCreators(a, dispatch))
    , [actions, dispatch]) as A;

Playground Link

使用对象

bindActionCreators 函数可以接受动作创建者的键控对象,无论如何,这就是您开始使用的对象。那么为什么不将它们全部绑定并获取我们需要的那些呢?

我们不再需要使用这种方法的任何as 断言,因为bindActionCreators 会自行返回正确的类型。我们从redux 导入类型ActionCreatorsMapObject 作为我们的通用A 将扩展的基础。

function useActions<A extends ActionCreatorsMapObject<any>>(
  actions: A
): A 
  const dispatch = useDispatch();
  return useMemo(() => 
    return bindActionCreators(actions, dispatch);
  , [actions, dispatch]);

你现在的用法变成了:

const  doFoo, doBar  = useActions(actions);

Playground Link

【讨论】:

以上是关于返回此数组的泛型类型的类型提示数组的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中的泛型类是啥东西?

Swift 中的泛型数组

TS泛型类、泛型接口、泛型函数

java中如何得到泛型参数的class?

java 定义泛型类的问题

在 Typescript 的泛型类中初始化泛型类型