3

I have a React hook which is used for fetching data:

const useData = (fetchingFn) => {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  // ... handle loading data by calling `fechingFn()`, etc

  return {
    data,
    loading,
    error
  }
}

I'm trying to add some typescript sauce to it and am struggling a bit because I'm a bit new to typescript. If someone could point me in the right direction, I would be open to buying you a cookie.

I have added a type definition for the return value of the hook:

type UseDataReturnType = {
  error: Error | null
  loading: boolean
  data: any | null
}

const useData = (fetchingFn: () => Promise<any>): UseDataReturnType  => {
...

You'll notice that I have two any types currently.

I think that this one: fetchingFn: () => Promise<any> may be okay because I don't want to limit the data types that can be used w/ the hook, theoretically, anything should be fine.

The trouble that I'm running into is that when using the hook, all of the type data is lost so that when I try to access the data later, it is treated as an any type.

For a full picture here is an example usage of the hook:

const fetchLoggedInUser = async (): Promise<User> => {
  return db.get('users','bob'
}

const MyView = (): JSX.Element => {
  const { loading, data, error } = useData(fetchLoggedInUserProfile)

  // the data should be of type `User|null` here but instead, it is `any`
}
1

1 Answer 1

2

You can strongly type the return type of the invocation using generics. For that you will have to pass in the type that the promise will resolve to and the hook consumes the type and passes along conserving the type info.

This is how you pass in the type information.

// pass along the type info to the hook.

//** Usage when calling the hook **//
// The type is passed along in <>
const { loading, data, error } = useData<User>(fetchLoggedInUserProfile);

//** Hook Definition **//
// TData is the generic type. It can be named anything
// The promise is expected to return type that is passed in which is TData in the // definition, but User when the hook is used
// And lastly you pass in the captured type along to the return type, as the 
// return type contains some additional meta info along with the original return type.
const useData = <TData>(fetchingFn: () => Promise<TData>): UseDataReturnType<TData>  => {
}

//** Type consuming the generic **//
type UseDataReturnType<TData> = {
  error: Error | null
  loading: boolean
  data: TData | null
}
Sign up to request clarification or add additional context in comments.

1 Comment

This works great. Thanks a million, Sushanth!

Your Answer

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