DEV Community

Cover image for How to configure Redux-Saga call return type definitions from Promisses in ReactJs or React Native Apps
heroneto
heroneto

Posted on

How to configure Redux-Saga call return type definitions from Promisses in ReactJs or React Native Apps

When we use Redux-Saga to configure Side-effects, sometimes we need want to get type definitions of our API or Script Promisses, in some cases this will be very usefull for productivity and code consistency.

We have multiple solutions, but in my recently search, this is the most simple and don't need aditional npm packages.

Let's suposes that we have a API Call code write like this:

File: Login.js

import instance from '../intance'
import { AxiosResponse } from 'axios'

interface ReturnContract {
  id: string,
  fullName: string,
  email: string,
  admin: boolean,
  username: string,
  active: boolean,
  tokens: {
    accessToken: string,
    refreshToken: string
  }
}

interface LoginService {
  (username: string, password: string): Promise<AxiosResponse<ReturnContract>>
}

export const login : LoginService = async (username: string, password: string) => {
  return await instance.post('/login', {
    username,
    password
  }) 
}
Enter fullscreen mode Exit fullscreen mode

In this code we simple call a API with instance of Axios, configured like bellow:

File: instance.js

import axios from 'axios'

const HOST = __DEV__ ? "[HERE OUR DEV HOST ENDPOINT]" : "[HERE OUR PROD HOST ENDPOINT]"
const instance = axios.create({
  baseURL: HOST
})

export default instance
Enter fullscreen mode Exit fullscreen mode

The rest of type definitions of Login.js, is using type definitions of Axios with AxiosResponse, passing our interface ReturnContract.

The AxiosResponse could be imported from axios lib.

Now, lets go to Sagas file, we have this code:

export function* login(action: Effect){
  try {
    const { username, password } = action.payload.data
    const result = yield call(loginService, username, password)

    const data = {
      response: "Login com sucesso",
      httpCode: result.status
    }
    const { tokens, ...user } = result.data
    yield setUser({
      ...user,
      isLogged: true
    })
    yield setAccessToken(tokens.accessToken)
    yield setRefreshToken(tokens.refreshToken)
    yield put(successLogin(data))
  } catch (error) {
    console.log(error.response)
    const data = {
      response: "Usuário ou senha incorretos, verifique os campos e tente novamente.",
      httpCode: error.response.status
    }
    yield put(failureLogin(data))
  }
}

Enter fullscreen mode Exit fullscreen mode

If we put the cursor mouse hover result, we will see this type definitions:
image

Ok, now we need to do this:

1 - Import SagaReturnType from 'redux-saga/effects'

import { Effect, put, call, SagaReturnType } from 'redux-saga/effects';
Enter fullscreen mode Exit fullscreen mode

2 - Create new Type definitions of return of result.

type LoginServiceResponse = SagaReturnType<typeof loginService>

Enter fullscreen mode Exit fullscreen mode

Take a look to parameter passed to SagaReturnType, is our Login.js function imported.

3 - Use this type definition in result:

type LoginServiceResponse = SagaReturnType<typeof loginService>

export function* login(action: Effect){
  try {
    const { username, password } = action.payload.data
    const result : LoginServiceResponse = yield call(loginService, username, password)
    const data = {
      response: "Login com sucesso",
      httpCode: result.status
    }
    const { tokens, ...user } = result.data
    yield setUser({
      ...user,
      isLogged: true
    })
    yield setAccessToken(tokens.accessToken)
    yield setRefreshToken(tokens.refreshToken)
    yield put(successLogin(data))
  } catch (error) {
    console.log(error.response)
    const data = {
      response: "Usuário ou senha incorretos, verifique os campos e tente novamente.",
      httpCode: error.response.status
    }
    yield put(failureLogin(data))
  }
}
Enter fullscreen mode Exit fullscreen mode

The final code should be as follows:

import { Effect, put, call, SagaReturnType } from 'redux-saga/effects';
import {
  login as loginService
} from '@core/services/apis'

import {
  setUser,
  setRefreshToken,
  setAccessToken,
} from "@core/services/storage"

import {
  failureLogin,
  successLogin
} from './actions';


type LoginServiceResponse = SagaReturnType<typeof loginService>

export function* login(action: Effect){
  try {
    const { username, password } = action.payload.data
    const result : LoginServiceResponse = yield call(loginService, username, password)
    const data = {
      response: "Login com sucesso",
      httpCode: result.status
    }
    const { tokens, ...user } = result.data
    yield setUser({
      ...user,
      isLogged: true
    })
    yield setAccessToken(tokens.accessToken)
    yield setRefreshToken(tokens.refreshToken)
    yield put(successLogin(data))
  } catch (error) {
    console.log(error.response)
    const data = {
      response: "Usuário ou senha incorretos, verifique os campos e tente novamente.",
      httpCode: error.response.status
    }
    yield put(failureLogin(data))
  }
}
Enter fullscreen mode Exit fullscreen mode

Now if we hover the mouse cursor in result.
image

Now we have all type definitions of API Return data and Axios Lib:
image

image

I think this will be helpfull to use in some projects that don't have too much modifications in API returns, or to use in some API enpoints.

Hope it helped.

Credits:

Typescript, Redux-Saga and Promises

NoriSte/redux-saga-typeguard.ts

Top comments (0)