Firstly you will need a type parameters that will capture the type of the input argument type.
function createAction<Payload, Type extends string>(type: Type): (payload: Payload) => ({
type: Type;
payload: Payload;
}) {
return (payload: Payload) => ({ type, payload });
};
interface Payload {
howAreYou: boolean;
}
const RequestName = 'GoodThanksHowAreYou';
const action = createAction<Payload, typeof RequestName>(RequestName);
Playground Link
The problem with this solution is that it does not allow you to specify only one of the type parameters, you mist specify both (the <Payload, typeof RequestName> part in the call). This is because Typescript does not allow for partial inference, either all types parameters are specified, or all are inferred.
There can be two solutions to this. The first one is to use function currying, so we can have the first type parameter inferred and the second specified. This works but leads to a somewhat ugly call site:
function createAction<Type extends string>(type: Type) {
return <Payload,>() => (payload: Payload) => ({ type, payload });
};
interface Payload {
howAreYou: boolean;
}
const RequestName = 'GoodThanksHowAreYou';
const action = createAction(RequestName)<Payload>();
The other solution is to use a dummy value to represent the type. This is just to let TS infer the type from the parameters. This can be as simple as just asserting null is whatever type we want, or we could hide the ugliness behind some other construct:
function createAction<Payload, Type extends string>(type: Type, payloadType: Payload) {
return (payload: Payload) => ({ type, payload });
};
interface Payload {
howAreYou: boolean;
}
const RequestName = 'GoodThanksHowAreYou';
const action = createAction(RequestName, null! as Payload);
Playground Link
Or:
class Type<T> { __dummy!: T }
function type<T>(){ return new Type<T>() }
function createAction<Payload, T extends string>(type: T, payloadType: Type<Payload>) {
return (payload: Payload) => ({ type, payload });
};
interface Payload {
howAreYou: boolean;
}
const RequestName = 'GoodThanksHowAreYou';
const action = createAction(RequestName, type<Payload>());
Playground Link