Current Typescript Version: 2.6.2
I am in the process of enhancing the type safety of redux beyond what is provided by default typedefs, while also streamlining some of the redundant code. I believe I am edging closer to my desired setup, with just one issue remaining. This is the current state of my implementation:
// Definition for Action based on redux typedefs
interface Action {
type: any;
}
// Customized Action type using generics
// T is expected to be a string literal
// P is optional and defaults to undefined
interface TypedAction<T extends string, P = undefined> extends Action {
readonly type: T;
readonly payload: P;
}
// Function that generates common action creators
// Takes a TypedAction as its generic argument to infer
// the required payload in the returned action creator
function makeActionCreator<T extends TypedAction<any, any>>(
type: T['type'],
): (p: T['payload']) => T {
return payload => ({ type, payload } as T);
}
//=================
// Example usage //
//=================
interface EmailPasswordCredential {
readonly email: string;
readonly password: string;
}
enum SignUpActionType {
executeSignUp = 'SignUp/executeSignUp',
reportSuccess = 'SignUp/reportSuccess',
reportError = 'SignUp/reportError',
}
////
// Action Types
////
// Sign-up action
// requires an email and password to be specified
type ExecuteSignUpAction = TypedAction<
SignUpActionType.executeSignUp,
EmailPasswordCredential
>;
// Success action
// Does not require a payload
type ReportSignUpSuccessAction = TypedAction<SignUpActionType.reportSuccess>;
// Error action
// Triggered when something fails (e.g., a 400 error)
// The error is passed back as the payload
type ReportSignUpErrorAction = TypedAction<SignUpActionType.reportError, Error>;
////
// Action Creators
////
const signUp = makeActionCreator<ExecuteSignUpAction>(
SignUpActionType.executeSignUp,
);
const reportSignUpSuccess = makeActionCreator<ReportSignUpSuccessAction>(
SignUpActionType.reportSuccess,
);
const reportSignUpError = makeActionCreator<ReportSignUpErrorAction>(
SignUpActionType.reportSuccess, // this correctly causes an error due to type mismatch
);
// the real problem:
// Correctly throws an error as EmailPasswordCredential is required
signUp();
// should ideally work without any arguments
reportSignUpSuccess();
// Resolves the type error but seems unnecessary
reportSignUpSuccess(undefined);
For a detailed example with syntax highlighting and inline errors, click here.
Is there a solution to resolve the "Expected 1 arguments, but got 0" issue? Is the setup of TypedAction
strange by defining undefined as the default?