根据参数中的属性强制执行函数的返回类型

时间:2018-10-19 18:42:42

标签: typescript typescript-typings

如下面的自包含代码片段(or here on Typescript Playground)所示,我想基于returnType参数的action道具在函数上强制执行返回类型。但是,我想证明returnType那个 returnType的正确action,而不仅仅是任何{{1} }。 向下滚动到代码段的底部,以了解我的意思:)

returnType

1 个答案:

答案 0 :(得分:1)

TypeScript不会narrow type parameters通过类型保护。这意味着支票action.type === "type1"确实缩小了action.type,但没有缩小T,因此返回类型仍然像联合类型void | {foo: "bar"}。 @RyanCavanaugh said显然不是一个容易解决的问题:

  

“正确”的做法是显而易见的,但是需要对我们如何处理类型参数进行大量的修改,同时产生一致的负面[性能]影响,而对实际的面向用户的行为却没有相应的正面影响一侧。

因此您必须解决它。一种方法是在每个类型保护的子句中手动声明返回类型:

type Ret<T extends GameActionTypes> = 
  FindByTag<ActionType<gameActions>, {type: T}>["returnType"];

export function executeAction<T extends GameActionTypes>(
  action: ActionType<gameActions>
): Ret<T> {
  if (action.type === "type1") {
    type R = Ret<typeof action.type>;
    return undefined as R; // okay
  } else if (action.type === "type2") {
    type R = Ret<typeof action.type>;
    return undefined as R; // error
  }
}

请注意,每个受保护的子句中的本地类型别名R不同,断言在一种情况下成功,而在另一种情况下失败。我不确定是否有人比这更容易使用类型安全的解决方案。

希望至少有一些帮助;祝你好运!


更新

因此,我没有意识到action参数不是通用的(我太关注实现内部的返回类型问题)。这意味着您有两个问题:在实现中推断返回值的正确类型,在调用函数时推断返回值的正确类型。现在让我们解决后者。

首先,如果要基于函数参数推断不同的泛型类型,则还需要将该参数也设为泛型类型。最好的结果是当参数类型与通用类型参数相同(而不是类型参数的某些复杂函数)时。因此,让我们这样做:

export function executeAction<A extends ActionType<gameActions>>(
  action: A
): A["returnType"] {
  const actionUnion: ActionType<gameActions> = action; // remove generic
  if (actionUnion.type === "type1") {
    type R =  Ret<typeof actionUnion.type>
    return undefined as R;
  } else if (action.type === "type2") {
    type R =  Ret<typeof actionUnion.type>
    return undefined as R;
  }
}

请注意,如何为操作指定类型A,因此返回值仅为A['returnType']。从呼叫者的角度来看,这现在非常简单,应该可以按您期望的方式工作:

declare const t1: TEST1;
const ret1 = executeAction(t1); // void
declare const t2: TEST2;
const ret2 = executeAction(t2); // {foo: "bar"}

该函数的实现需要进行一些调整...具体来说,泛型现在是动作类型A,而不是动作类型T type属性。缩小甚至更不容易实现。解决方法是将action分配给非泛型变量actionUnion,这只是A扩展的并集类型。然后,return undefined as Ret<typeof actionUnion.type>的缩小与以前一样(令人沮丧)。

好的,希望也能有所帮助。再次祝你好运。