想象一下以下简化的设置:
import { Action, AnyAction } from 'redux'; // interface Action<Type> { type: Type } and type AnyAction = Action<any>
export type FilterActionByType<
A extends AnyAction,
ActionType extends string
> = A['type'] extends ActionType ? A : never;
type ActionUnion = Action<'count/get'> | Action<'count/set'>;
type CountGetAction = FilterActionByType<ActionUnion, 'count/get'>;
// expected: Action<'count/get'>
// received: never
有没有办法做到这一点?(typescript 3.7是一个选项)
3条答案
按热度按时间l3zydbqr1#
您希望
FilterActionByType<A, T>
采用一个联合类型A
并分别作用于每个成员,然后采用所有结果并将它们联合到一个新的联合中。这意味着您希望FilterActionByType<A, T>
* 在联合上分发 *(至少在A
中)。您可以使用分布式条件类型来完成此操作,方法是确保条件类型的格式为type FilterActionByType<A, T> = A extends ...
。将裸A
作为选中的类型会触发所需的分发。但是:你的条件类型是
type FilterActionByType<A, T> = A["type"] extends ...
的形式,其中A
被属性查找“覆盖”,因此不是分布式的。这意味着A["type"] extends ActionType
采用A
的整个联合值,即(在您的情况下)ActionUnion
。ActionUnion["type"] extends "count/get"
变成("count/get" | "count/set") extends "count/get"
,这是假的。(X extends (X | Y)
总是为真,但(X | Y) extends X
一般不为真。)所以你得到never
。将你的定义转换为分布式条件类型的最简单的方法是将你的定义 Package 在
A extends any ? ... : never
中:或者你可以重构你原来的条件类型,使其成为分布式的,而不 Package 它:
校验
A extends {type: ActionType}
是A["type"] extends ActionType
的分布式版本。无论哪种方式都应该为您工作,但后者可能更干净。
好吧,希望能帮上忙;祝你好运!
链接到代码
ffdz8vbo2#
Extract<T, U>
对此非常有用,并且比条件类型简单得多。对于下面的示例,您可以将其视为“过滤器”:可能不太可能对OP问题有用,但也有一些很酷的功能用于过滤Map类型(来自TS 4.1)。
2w3rbyxf3#
Piotr Lewandowski的最佳解决方案: