Saya memiliki kait reaksi sederhana yang menerima satu argumen, fungsi asinkron. Ini berfungsi, namun saya tidak mendapatkan inferensi tipe apa pun saat menggunakan pengait. Secara khusus, saya mencoba membuat TypeScript menyimpulkan jenis argumen panggilan balik yang diteruskan. Saya telah memberikan kode di bawah ini dan penggunaan fungsi saya saat ini.

Kailnya:

import { useCallback, useState } from "react";

type UseAsync<T> = [{ result: T; loading: boolean; error: string }, (...args) => void];

export const useAsync = <T>(asyncFn: (...args) => Promise<T>): UseAsync<T> => {
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);

  const callback = useCallback(
    async (...args) => {
      try {
        setLoading(true);

        const result = await asyncFn(...args);

        setResult(result);
      } catch (e) {
        setError(e);
      } finally {
        setLoading(false);
      }
    },
    [asyncFn]
  );

  return [{ result, loading, error }, callback];
};

export default useAsync;

Penggunaan saya:

const [{ result, loading, error }, postOrder] = useAsync((data: INewOrderFormData) =>
    Axios.post("/api/order", data)
);

Ketika saya mengarahkan kursor ke "postOrder" di VSCode saya melihat const postOrder: (...args: any[]) => void di mana args didefinisikan sebagai any[] ketika itu harus merujuk jenis argumen, jika ada, dari fungsi yang diteruskan ke hook.

1
Moussa Harajli 23 April 2021, 01:43

1 menjawab

Jawaban Terbaik

Anda dapat melacak jenis argumen jika Anda menambahkan parameter generik tambahan A extends unknown[] ke UseAsync & useAsync, dan mengetikkan setiap kemunculan ...args dengannya.

Hasilnya akan terlihat seperti ini (saya harus mengubah beberapa jenis null, mungkin karena kode tidak dikompilasi dengan strictNullChecks):

type UseAsync<T, A extends unknown[]> =
  [{ result: T | null; loading: boolean; error: string }, (...args: A) => void];

export const useAsync = <T, A extends unknown[]>(asyncFn: (...args: A) => Promise<T>): UseAsync<T,A> => {
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<T | null>(null);
  const [error, setError] = useState<any>(null);

  const callback = useCallback(
    async (...args: A) => {
      try {
        setLoading(true);

        const result = await asyncFn(...args);

        setResult(result);
      } catch (e) {
        setError(e);
      } finally {
        setLoading(false);
      }
    },
    [asyncFn]
  );

  return [{ result, loading, error }, callback];
};

Saat diterapkan ke fungsi pengujian, tipe postOrder memiliki tipe argumen yang sebenarnya:

type INewOrderFormData = {}

const [{ result, loading, error }, postOrder] = 
  useAsync(async (data: INewOrderFormData, arg2: symbol) => 42);

type Test = typeof postOrder
// inferred type: (data: INewOrderFormData, arg2: symbol) => void

Taman bermain TypeScript

2
Oblosys 22 April 2021, 23:31