这个问题的规范答案取决于你的确切用例。我假设你需要Action
来准确评估你写的类型;也就是type: "DO_X"
的对象不是有任何形式的财产。这意味着createAction("DO_X")
应该是零参数的函数,而createAction("DO_Y")
应该是单个string
参数的函数。我还将假设您想要自动推断createAction()
上的任何类型参数,因此您不需要为Blah
的任何值指定createAction<Blah>("DO_Z")
。如果解除这些限制中的任何一个,则可以将解决方案简化为类似于@Arnavion提供的解决方案。
打字稿不喜欢物业值映射类型,但它高兴地物业这么做键。因此,让我们以一种为编译器可用来帮助我们的类型提供类型的方式构建Action
类型。首先,我们描述了有效载荷的每一个动作类型是这样的:
type ActionPayloads = {
DO_Y: string;
DO_Z: number;
}
我们还引入任何Action
类型,而有效载荷:
type PayloadlessActionTypes = "DO_X" | "DO_W";
(我已经添加了'DO_W'
型只是为了显示它是如何工作,但你可以删除它)。
现在,我们终于能够表达Action
:
type ActionMap = {[K in keyof ActionPayloads]: { type: K; payload: ActionPayloads[K] }} & {[K in PayloadlessActionTypes]: { type: K }};
type Action = ActionMap[keyof ActionMap];
的ActionMap
类型是一个对象,它的键是每个Action
的type
,并且其值是Action
工会的相应元素。它是Action
s与s的交点,以及Action
而不是s的交点。而Action
只是ActionMap
的值类型。确认Action
是您所期望的。
我们可以用ActionMap
帮我们输入createAction()
函数。那就是:
function createAction<T extends PayloadlessActionTypes>(type: T):() => ActionMap[T];
function createAction<T extends keyof ActionPayloads>(type: T): (payload: ActionPayloads[T]) => ActionMap[T];
function createAction(type: string) {
return (payload?: any) => (typeof payload === 'undefined' ? { type } : { type, payload });
}
这是一个重载函数与对应的Action
的type
要创建一个类型参数T
。前两个声明描述了两种情况:如果T
是type
的Action
而没有,则返回类型是返回正确类型Action
的零参数函数。否则,它是一个单参数函数,它采用正确类型的并返回正确类型Action
。实施(第三签名和身体)与你相似,不同之处在于,如果在没有通过它不添加的结果。
全部完成!我们可以看到,它的工作原理是期望:
var x = createAction("DO_X")(); // x: { type: "DO_X"; }
var y = createAction("DO_Y")("foo"); // y: { type: "DO_Y"; payload: string; }
var z = createAction("DO_Z")(5); // z: { type: "DO_Z"; payload: number; }
createAction("DO_X")('foo'); // too many arguments
createAction("DO_X")(undefined); // still too many arguments
createAction("DO_Y")(5); // 5 is not a string
createAction("DO_Z")(); // too few arguments
createAction("DO_Z")(5, 5); // too many arguments
你可以看到这一切在行动on the TypeScript Playground。希望对你有效。祝你好运!
您是否尝试过类似于(type:Type)的定义:(payload:Payload)=> {type:Type,payload:Payload}? –
@EmrysMyrooin这似乎并不奏效。类型被用作值。但仿制药似乎是朝着正确方向迈出的一步。 TypeScript如何知道'Type'和'Payload'来自'Action'? – daGrevis
何你在Typescript ...我没有检查过标签。我实际上不知道,我正在使用Flow进行打字! –