Using TypedActionDefinitions

Part 1: Creating a Definition

The first step to integrating TypedActions into your Redux application is to create a Definition, which marries a unique Action type string (like "AddMessage") to the associated payload (like { message: string, author: string }).

Note: The syntax for defineAction is just a little awkward, with the double sets of (). There is a good reason for the syntax choice, so just be careful not to forget all the pieces! Written in one line, the correct syntax is defineAction("Foo")<FooPayload>().

The utility function isType shows how to use a Definition as a type guard to detect Actions that match it.

Example

// actions.ts
import { defineAction } from "redoodle";

export const AddMessage = defineAction("AddMessage")<{
  message: string;
  author: string;
}>();

// ... all the other action definitions used by your app

TypeScript signature

function defineAction<E extends string>(type: E): <T = undefined>() => TypedActionDefinition2<E, T>;

Part 2: Using Your Definitions

The most important thing a Definition does is to be a factory to stamp instances of Actions that conform to the Definition.

A Definition is a callable function which, given a payload, will create an Action object ready to dispatch. The Definition itself is typesafe, which means that a payload that has incorrect, has extra, or is missing keys will raise compile-time errors.

The created Action is a plain old Redux Action that's ready to go straight to a Store's dispatch(). While this could be the end of the story for Redoodle, Redoodle also provides powerful utilities for reducing Actions based on Definitions. The following section Reducing Actions walks through how to use the TypedReducer utility to create a Redux Reducer that leverages the power of typed Action Definitions.

Example

import { AddMessage } from "./actions";

// assuming AddMessage is created using defineAction(), as in the above section:
//
// const AddMessage = defineAction("AddMessage")<{
//   message: string;
//   author: string;
// }>();
//

store.dispatch(
  AddMessage({
    message: "Hello Redoodle",
    author: "crazytoucan"
  }),
);

// The code above dispatches the following action to your store:
//
//   {
//     type: "AddMessage",
//     payload: {
//       message: "Hello Redoodle",
//       author: "crazytoucan"
//     }
//   }
//
// Most importantly, all of the fields of the generated `action` are type-aware at compile time.
// Using ~> to denote TypeScript type inferencing:
//
//    action.type ~> "AddMessage"    (the specific string literal)
//    action.payload ~> { message: string, author: string }
//    action.payload.message ~> string
//    action.payload.whoops ~> Error [ts] Property 'whoops' does not exist

TypeScript signature

type TypedActionDefinition2<E extends string, T> = {
    <M>(payload: T, meta?: M): {
        type: E;
        payload: T;
        meta: M;
    };

    TYPE: TypedActionString<T, E>;
    __PAYLOAD: T;
} & (T extends undefined ? {
    (): {
        type: E;
        payload: undefined;
    };
} : {});

results matching ""

    No results matching ""