How to configure Redux-Saga call return type definitions from Promisses in ReactJs or React Native Apps
Published: 2021-02-21 13:10:26

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
  }) 
}
```

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
```

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))
  }
}

```

If we put the cursor mouse hover **result**, we will see this type definitions:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eszt1zsd95lk21ceusjq.png)

Ok, now we need to do this:

1 - Import SagaReturnType from 'redux-saga/effects'
```
import { Effect, put, call, SagaReturnType } from 'redux-saga/effects';
```

2 - Create new Type definitions of return of result.
```
type LoginServiceResponse = SagaReturnType<typeof loginService>

```
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))
  }
}
```

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))
  }
}
```

Now if we hover the mouse cursor in result.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8b154end2yaoqdtic16w.png)

Now we have all type definitions of API Return data and Axios Lib:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7hln4ls0xasgauoalh7e.png)
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpdlvmr2cy69dbh1dj9c.png)


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](https://medium.com/swlh/typescript-redux-saga-and-promises-b9792c575417)

[NoriSte/redux-saga-typeguard.ts](https://gist.github.com/NoriSte/936096262be7af6b6bd4cba7a71640d9)