简体   繁体   中英

How can infer types from either string or string array property

Given the following scenario:

type Action =
| { type: 'FOO' }
| { type: 'BAR' }

type Rule = {
   target: string | string[],
   consequence: (action:Action) => void
}

const rule1:Rule = {
  target: 'FOO',
  consequence: action => console.log(action) // { type: 'FOO' }
}

const rule2:Rule = {
  target: ['FOO', 'BAR'],
  consequence: action => console.log(action) // { type: 'FOO' } | { type: 'BAR' }
}

The action can be dispatched (eg with redux) and the rule can react to it. When the target matches the action.type then the consequence gets executed with the matching action.

The Question

I want that the rules consequence infers the right type. This can be done somehow by the target . But I don't know how. My current approach:

type Rule<Action> = {
  target: string | string[],
  consequence: (action:Action) => void
}
const rule:Rule<{ type: 'FOO' }> = ...

But I need a way where I can write

const rule:Rule<{ type: 'FOO' } | { type: 'BAR' }> = ...

and the correct type gets inferred by the rules target

This is the best I could figure out. You'll have to abandon target being a single value, and rely on it always being an array, even if that array has a single element. There might be a way to get it to work with function overloads, but I couldn't get it to work.

type ActionType = "FOO" | "BAR";

type Action<T extends ActionType> = { type: T };

function createRule<T extends ActionType[]>(target: T) {
  return {
    target,
    consequence: (action: Action<T[number]>) => console.log(action)
  };
}

const foo = createRule(["FOO"]);
const bar = createRule(["FOO", "BAR"]);

foo.consequence({ type: "FOO" });
foo.consequence({ type: "BAR" }); // nope
bar.consequence({ type: "FOO" });
bar.consequence({ type: "BAR" });
bar.consequence({ type: "BAZ" }); // nope

https://codesandbox.io/s/dawn-wildflower-03cbq?file=/src/index.ts

Using a function to create the rule lets you use generics without having to repeat yourself by specifying it as both a type and a value every time you create a new rule.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM