Общие реквизиты: почему этот тип не выводится правильно?

#reactjs #typescript

#reactjs #typescript

Вопрос:

У меня есть очень простой Demo компонент с реквизитом, принимающим общий параметр TVariables :

 type Variables = {
  limit: number;
  page: number;
  search?: string | null;
  sort?: string | null;
  sortOrder?: number | null;
};

type Props<TVariables extends Variables> = {
  variables: TVariables;
  setVariables(variables: TVariables): void;
};

function Demo<TVariables extends Variables>(props: Props<TVariables>) {
  return null;
}
 

Но затем, когда я пытаюсь использовать его в сочетании с useState , он не выводит TVariables правильно :

 function useListVariables<T>(init: T) {
  return React.useState<Omit<T, keyof Variables> amp; Variables>({
    search: null,
    sort: "_id",
    sortOrder: 1,
    limit: 10,
    page: 1,
    ...init
  });
}

export default function App() {
  const [variables, setVariables] = useListVariables({
    test: "demo",
    sortOrder: -1,
    limit: 4
  });

  return <Demo variables={variables} setVariables={setVariables} />;
}
 

В предпоследней строке setVariables подчеркивается как ошибка :

 (method) setVariables(variables: Variables): void
Type 'Dispatch<SetStateAction<Pick<{ test: string; sortOrder: number; limit: number; }, "test"> amp; Variables>>' is not assignable to type '(variables: Variables) => void'.
  Types of parameters 'value' and 'variables' are incompatible.
    Type 'Variables' is not assignable to type 'SetStateAction<Pick<{ test: string; sortOrder: number; limit: number; }, "test"> amp; Variables>'.
      Type 'Variables' is not assignable to type 'Pick<{ test: string; sortOrder: number; limit: number; }, "test"> amp; Variables'.
        Property 'test' is missing in type 'Variables' but required in type 'Pick<{ test: string; sortOrder: number; limit: number; }, "test">'.ts(2322)
App.tsx(41, 5): 'test' is declared here.
App.tsx(17, 3): The expected type comes from property 'setVariables' which is declared here on type 'IntrinsicAttributes amp; Props<Variables>'
 

Вот где это становится странным. Если я явно задам общий параметр для компонента, ошибка исчезнет :

 // This works

<Demo<typeof variables> variables={variables} setVariables={setVariables} />
 

Кроме того, если я перепишу реквизит таким образом, я тоже буду работать :

 // This works

<Demo variables={variables} setVariables={variables => setVariables(variables)} />
 

У меня есть ссылка на Codesandbox, чтобы вы могли попробовать сами: Codesandbox

Что здесь происходит и как я могу устранить ошибку, не задавая явно общий тип? Спасибо.

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

1. Я думаю, что это интересная вещь с точки зрения «вот интересная головоломка для вывода», но действительно ли явная передача параметра универсального типа действительно имеет большое значение?

2. @JaredSmith Я хочу понять эту «головоломку», вот что я хочу сказать.

3. Нет, это достаточно справедливо, поэтому я не понизил голос или VTC.