0

I've been playing around with TypeScript recently and string literals work great with Redux actions and reducers. e.g:

const INCREMENT = "INCREMENT";
type INCREMENT = typeof INCREMENT;

const DECREMENT = "DECREMENT";
type DECREMENT = typeof DECREMENT;

interface IncrementAction {
  type: INCREMENT;
}
interface DecrementAction {
  type: DECREMENT;
}

type Actions = IncrementAction | DecrementAction;

const reducer = (state = 0, action: Actions) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    case DECREMENT:
      return state + 1;
    default:
      return state;
  }
};

The problem I've stumbled upon is typing actions where the action name is imported from an npm module. So without any types, code would look like:

import { SOME_ACTION } from 'npm-packaged-with-actions';

const reducer = (state = null, action) => {
  switch (action.type) {
    case SOME_ACTION:
      return state + 1;
    default:
      return state;
  }
}

How would I define the TypesScript type for SOME_ACTION? The type definition file exports SOME_ACTION as a string, so I cannot create the type as:

type SOME_ACTION = typeof SOME_ACTION;

In this case SOME_ACTION is a type of string rather than a string literal, so the reducer action matching doesn't work.

brentatkins
  • 128
  • 8

2 Answers2

0

You can instruct the compiler to generate a definition file for your code and then provide the definition with your module. Doing so when you import the module the compiler will know about the types you defined in Typescript.

"compilerOptions": {
    "module": "commonjs",
    "declaration": true
}

More information about writing npm module in typescript you can find on this question

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
0

A very simple way of creating redux actions in Typescript is type guards. This package has done in a vey simple way by typing the key called "payload" of actions with a provided type.

So you define your action as

export const ActionA = defineAction<{ url: string }>('Action A');

// And you can dispatch the action as
dispatch(ActionA.get({ url: 'http://www.googlel.com' });

But for the action coming from another module you can do:

import { SOME_ACTION } from 'npm-packaged-with-actions';

// And you'll have an action based on the provided types
export const ActionOfModule = defineAction</* your desire type here */string>(SOME_ACTION);

// But again to this is an action creator, so to get the action you need to call "get" or "strictGet" from it
dispatch(ActionOfModule.strictGet('This is the payload of this action');
PRAISER
  • 793
  • 7
  • 15