简体   繁体   中英

How to write function type definitions for anonymous functions in typescript?

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 => {
    ...
  }
}}

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM