Flow - secure actions to ensure type safety

Currently implementing flow and looking to enhance the type safety of my reducers. I stumbled upon a helpful comment proposing a solution that seems compatible with my existing codebase: https://github.com/reduxjs/redux/issues/992#issuecomment-191152574

I attempted to adapt it using the %checks keyword in flow, but encountered some issues.

Snippet from my code:

export type Action<T> = {
  type: string,
  payload: T,
};

interface ActionCreator<P> {
  type: string;
  (payload: P): Action<P>;
}

export function actionCreator<P>(type: string): ActionCreator<P> {
  return Object.assign((payload: P) => ({ type, payload }), { type });
}

export function isActionOfType<P>(
  action: Action<any>,
  creator: ActionCreator<P>
): boolean %checks {
  return action.type === creator.type;
}

When incorporating it within the reducer function like this

(...)
case isActionOfType(action, getArticles):
  // action.payload still has an 'any' type
(...)

Is there a mistake on my end? Can the TypeScript solution be effectively applied in flow? Or do you recommend an alternative approach? If so, what suggestions can you offer?

Answer №1

When working with TypeScript, it's recommended to use an if statement instead of a case statement.

There is no strict requirement to use a case statement in Redux anymore, as the trend now leans towards utilizing if statements with type guards in TypeScript.

You might want to explore this alternative approach. Unfortunately, I can't offer much guidance on flow, but I can suggest following modern patterns for TypeScript that may align with practices in flow.

Additionally, consider looking into the official Redux Toolkit, which offers useful abstractions. While only partially flow-typed, its types could potentially meet your requirements or be enhanced further based on your needs.

Answer №2

To implement a type generic that links one string type with a payload type, consider using switch cases. It is important to note that switch cases are designed to test against strings in the case, not booleans, so utilizing them in the way shown may not work as expected.

One solution involves leveraging type refinement. By writing conditional JavaScript code, Flow can infer the structure of the payload. However, it is crucial to include all possible type payloads in your action parameter to ensure Flow understands the available structures for refinement. This approach helps clarify the variations in your reducer and specifies which cases should be handled.

try-flow

type AppT = {}

type ActionT<T, P> = {|
  type: T,
  payload: P,
|};

type PayloadA = {| a: string |};
type PayloadB = {| b: string |};

const initialState = {};

const reducer = (
  state: AppT = initialState,
  action: ActionT<'ACTION_A', PayloadA> | ActionT<'ACTION_B', PayloadB>,
): AppT => {
  switch (action.type) {
    case 'ACTION_A': {
      return {
        ...state,
        a: action.payload.a,
      };
    }
    case 'ACTION_B': {
      return {
        ...state,
        a: action.payload.a, // <-- it fails because type refines to PayloadB
        b: action.payload.b,
      };
    }
    default:
      return state;
  }
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a dynamic route in Node Express allows for flexible path handling

Is there a way to incorporate a dynamic route or path using the Express package? The challenge is that the path is an ID passed by the client and we have no control over it. const express = require('express'); const dynamicPath = express(); dyn ...

disable caching for xmlhttp request

One issue I am facing is with a JavaScript function that retrieves JSON data via an Ajax request. The problem I'm encountering is that the browser starts caching the response to this request, which means I am not getting the most recent data from the ...

Initiating PHP outcomes with the integration of JQUERY and Bootstrap

Currently, I am working on a Twitter search functionality that allows me to search for any content on Twitter. While the feature is functional, I am facing some challenges with displaying the results in the desired format. Ideally, I would like the results ...

Kineticjs is not performing up to par

I apologize if this question has already been asked, but I haven't been able to locate it. I am working on a project that involves a canvas displaying approximately 400-500 rectangles, each ranging in height and width from 20-30 pixels. The goal is t ...

Using AngularJS to update attributes in an HTML tag within a string

My string contains HTML tags : var str = "<div><p></p><p><i>blabla</i></p><p><i><b>blaaaaaablaaaaa</b></i></p><iframe src='urlAAA' height='400' width=&ap ...

Working with Javascript: Navigating a dynamic array of elements

I need to reorganize a form on my webpage. Currently, all the fields are in one table and I want to move them around based on certain conditions. However, when I try to loop through the elements and move them, the javascript array is changing and causing m ...

Error: string literal left incomplete with spaces only

I am attempting to run parameters from a JavaScript function, but I am encountering an issue with quotes when there is a white space present. This error specifically pertains to Mozilla: SyntaxError: unterminated string literal Below is the relevant p ...

Avoid data duplication or triplication by implementing a pop-up loop when adding new information

Seeking assistance in identifying the line of code that is causing data duplication or triplication when adding information in a pop-up form. The New/Update/Delete functions are functioning correctly, except for the Add function. The problem arises when i ...

Using AJAX to query a database and updating a div tag with the submitted form entries

I need assistance in setting up a webpage with an AJAX form. The idea is that upon submission, the form's values will be used to search and query a database for results, which will then be displayed in the same DIV as the form. Any guidance or help o ...

Tips for sending multiple variables in a loop as JSON data through an AJAX request

I need assistance with the code below. I am trying to pass the value[i] into a data string in a json ajax post submit. Essentially, my goal is to gather all the checked values in a form and insert them into an existing json data string using ajax. This is ...

Not quite sure about the best way to showcase the results // using JavaScript

My code is posted below. I am trying to achieve a functionality where, upon clicking the 'Calculate Price' button, the results showing the number of cars, type of cars, and their respective prices are displayed beneath the button. Despite this be ...

React / Next.js Rendering Problem, Data Discrepancy Between Client and Server

A new feature has been added to a webpage where an image background and a city name are displayed on top of it. The data file that generates these image backgrounds and city data consists of a standard array of objects. The challenge lies in dynamically l ...

Creating a Modal in React without the need for a button to trigger it

I am working on implementing a model using the React Material UI library to display information on the landing page when a user logs in. However, I am facing an issue with closing the modal once it appears despite using a timeout trigger. const[post,setP ...

Tips on displaying JSON data in the browser console using console.log for API consumption

I'm having trouble creating an api to output data parsed from an xml file. When I console.log the necessary data, it shows up fine, but when I try to display it in the browser, I only get an empty array. Any suggestions on what could be causing this i ...

Having trouble sending data to API with Node, Express, and vanilla JavaScript POST form

I am currently utilizing Node JS along with Express JS in order to implement a form submission that pushes data into the database. Below is my form structure <form action="/pokedex/register/poke_submission" method="POST"> ...

Vue appears to be having trouble waiting for the axios Post request

While testing a login request, I encountered an issue where jest did not call the mock: This is my test : const User = '123123' jest.mock('axios', () => ({ get: jest.fn(), post: (_url, _body) => new Promise((resolve, reject ...

Basic Tallying Code in JavaScript

Hi, I am currently working on creating a basic counter using HTML / CSS and Javascript. Unfortunately, my Javascript code is not functioning correctly, even after trying various solutions found online. I attempted to include "async" but it appears that my ...

Ensuring TypeScript's strict null check on a field within an object that is part of an

When using TypeScript and checking for null on a nullable field inside an object array (where strictNullCheck is set to true), the compiler may still raise an error saying that 'Object is possibly undefined'. Here's an example: interface IA ...

Can you provide a tutorial on creating a unique animation using jQuery and intervals to adjust background position?

I am attempting to create a simple animation by shifting the background position (frames) of the image which serves as the background for my div. Utilizing Jquery, I aim to animate this effect. The background image consists of 6 frames, with the first fr ...

The importance of handling undefined values in TypeScript and React

There is a condition under which the IconButton element is displayed: {value.content && <IconButton aria-label="copy" onClick={() => copyContent(value.content)}> <ContentCopy /> </IconButton> } However, a ...