Typescript: передача выведенного типа через useCallback React

#javascript #typescript

#javascript #typescript

Вопрос:

Пример:

 function useCallback(fn) {
  return fn;
}

type ApiData = {
  '/user': { user: any },
  '/post': { post: any },
};

function useApi<Path extends keyof ApiData>(
  path: Path,
  opts: {
    cb?: (data: ApiData[Path]) => void,
  },
) {}

useApi('/user', { cb: ({ user }) => null }); // ok
useApi('/user', { cb: ({ post }) => null }); // Property 'post' does not exist on type '{ user: any; }'
useApi('/user', { cb: useCallback(({ user }) => null) }); // ok
useApi('/user', { cb: useCallback(({ post }) => null) }); // should have error
  

Игровая площадка TS: https://www.typescriptlang.org/play?noImplicitAny=false#code/GYVwdgxgLglg9mABCAzgUwMIEMA2OBGWEA1gBTBgCUiA3gFCKIBOaUITSFA3HQL510oATwAOaRAEERMACJYoWRAF5aDRAHIA9KjRN1ALlrJ0TQ1jBDEvADRqtIuCigGjDp2YtXbvHnVCRYBGM0KRgAHgAFeQALRDQADyg0MAATFERiNCE4YElpOQUAPlI1ERjDKKho20Y4ESgUQ3pGRgh8AH5DUhT5LENQgqwAbUrogF1qJULEADc4GBSarzpqGn46HVDSLR09ayM2rppgpitJ6bAQPDOuRE1NRDhiDfQtnZN1fePDxFJjtygZ2UFyuOBudweESYdV0wg0APUiBScDQ6TAcEBCRgTkeSGEYg0x12HiEt146heIWk220Hy iB OmweEIJFIfxOQKmiEueGovEot3uj2em2p710nwO EMTNwBCIZA5AK5IL54OFKGicCuKUQ0SwM3EumhTAEQA

В этом примере, без useCallback , TS смог автоматически определить тип типа аргумента обратного вызова. Однако при useCallback этом он теряет эту способность.

Интересно, что если я сделаю cb свойство обязательным, то TS сможет определить тип аргумента:

 function useApi<Path extends keyof ApiData>(
  path: Path,
  opts: {
    cb: (data: ApiData[Path]) => void, // <- removed the "?"
  },
) {}

useApi('/user', { cb: useCallback(({ post }) => null) }); // Property 'post' does not exist on type '{ user: any; }'
  

Как я могу заставить TS выводить аргумент обратного вызова?

Комментарии:

1. С точно такой же проблемой. Не уверен, почему это было отклонено. Каким-то образом вывод типа перестает работать, когда параметр является необязательным.

Ответ №1:

Это не имеет значения с ? необязательным оператором

Анализатор Typescript правильно определяет, что это за типы.

Поскольку вы указали первый параметр функции useApi как '/user' , он не будет работать.

Измените его на,

 useApi('/post', { cb: useCallback(({ post }) => null) });
  

Это сработало бы.

Комментарии:

1. В этом случае OP ожидает ошибку, см. // должен иметь комментарий к ошибке . Ошибка не отображается, поскольку тип обратного вызова расширен