2

I am using redux-thunk in my react-native(typescript) redux project. And I am using thunkWithExtraArgument Helper to provide the reference of my apollo client variable and since I get three-argument for the return function that is

...
return async (dispatch, getState, client) => 
...
// and with typescript
import { NormalizedCacheObject } from 'apollo-cache-inmemory'
import ApolloClient from 'apollo-client'
import { Dispatch } from 'redux'

import { ReduxStore } from '../interfaces/redux.ts';

...
return async (dispatch: Dispatch, getState: () => ReduxStore, client: ApolloClient<NormalizedCacheObject>): Promise<void>) => {
...
}

that I have to type a lot of code already everywhere so is there any solution to this.

Currently, I am doing is this:


import { NormalizedCacheObject } from 'apollo-cache-inmemory'
import ApolloClient from 'apollo-client'
import { Dispatch } from 'redux'
import { ReduxStore } from '../interfaces/redux.ts'

// actually i outsources both GetState and Client types
type GetState = () => ReduxStore
// where ReduxStore is custom defined interface
type Client = ApolloClient<NormalizedCacheObject>

const fetchSomeData = (id: string) => {
  return async (dispatch: Dispatch, getState: GetState, client: Client): Promise<void>) => {
    ...
  }
}

What I tried and need is that

...
export type Thunk = (dispatch: Dispatch, getState: () => ReduxStore, client: ApolloClient<NormalizedCacheObject>): Promise<void>
...

// action creator

const fethcSomeData = (id: string) => {
  return async (dispatch, getState, client): Thunk => {
    ...
  }
}}

0

2 Answers 2

3

You should be able to use contextual typing to infer the parameter types for you, by having the compiler realize that you want a value of type Thunk. Since I don't have react/redux typings (and the question is really about the general issue I think) I will use something made up:

type Spronk = (x: string, y: number, z: boolean) => Promise<string>;

The most type-safe way is to annotate a variable of this type and return it:

const fethcSomeData = (id: string) => {
  const ret: Spronk = async (x, y, z) => (z ? x : y.toFixed());
  return ret;
};

Or you could use a type assertion which is more terse but a bit less safe (it will let you narrow the value):

const fthecSomeData = (id: string) => {
  return <Spronk>(async (x, y, z) => (z ? x : y.toFixed())); 
};

Either way should hopefully work for you. Good luck!


UPDATE: Here's what I mean by unsafe. The following is an error:

const errorCaught: Spronk = async (x, y, z) => (z ? x : y); // error!
// (string | number) is not assignable to string

I've annotated the type of errorCaught to be Spronk. The compiler recognizes that I am returning a string | number instead of a string, meaning that errorCaught is not a true Spronk, but a wider type. It is an error to annotate a variable to be narrower than the value you assign to it.

const errorSuppressed = <Spronk>(async (x, y, z) => (z ? x : y)); // no error

Here, I've asserted the type of errorCaught to be Spronk. The compiler still recognizes that the value is wider than a Spronk, but type assertions specifically allow you to say that a value is of a narrower type than the compiler can verify. There are times when such flexibility is useful, but it is dangerous. In the case of errorSuppressed we've deliberately lied to the compiler, which can get us in trouble at runtime:

errorSuppressed("a", 1, false).then(s => console.log(s.charAt(0))); // compiles, but
// at runtime: "TypeError, s.charAt is not a function"

Hope that makes sense.

Link to code

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, sir both solutions work for me second solutions seems little junky funky but little useful and what does it mean to bit less safe sir? (i am new to typescript)
Updated with explanation about how type assertions can be used unsafely
0

As @jcalz's second option type assertion now the latest typescript compiler warns about this as

Type assertion using the '<>' syntax is forbidden. Use the 'as' syntax instead

so using it this way is preferable


const fetchSomeData = (id: string) => {
  return <Spronk>(async (x, y, z) => (z ? x : y.toFixed())); 
};

to

const fetchSomeData = (id: string) => {
  return (async (x, y, z) => (z ? x : y.toFixed())) as Spronk; 
};

1 Comment

It is forbidden in .tsx files, not in general.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.