Как правильно ввести общий компонент функции реакции в TypeScript

В следующем Машинопись площадка пример Я попытался обобщить функциональный компонент Element в GenericElement компонент, но TypeScript жалуется на синтаксис.

Как правильно ввести общий компонент функции реакции в TypeScript, используя подход определения типа React.FC?

import React from 'react';

type PropsType = {
  id: string,
    value: string,
};

type GenericPropsType<keyType> = {
  id: keyType,
    value: string,
};

const Element: React.FC<PropsType> = ({id, value}) => {
    return <div>{id.toString()}={value}</div>;
};

const GenericElement: React.FC<GenericPropsType<keyType>> = <keyType = string>({id, value}) => {
    return <div>{id.toString()}={value}</div>;
};
Type 'Element' is not assignable to type 'FC<GenericPropsType<any>>'.
  Type 'Element' provides no match for the signature '(props: PropsWithChildren<GenericPropsType<any>>, context?: any): ReactElement<any, any> | null'.
Cannot find name 'keyType'.
Property 'keyType' does not exist on type 'JSX.IntrinsicElements'.
Cannot find name 'id'.
Left side of comma operator is unused and has no side effects.
Cannot find name 'value'.
Cannot find name 'id'.
Cannot find name 'value'.
Identifier expected.
Unexpected token. Did you mean `{'>'}` or `&gt;`?
Expression expected.
Unexpected token. Did you mean `{'}'}` or `&rbrace;`?
JSX element 'keyType' has no corresponding closing tag.
'</' expected.
'Element' is declared but its value is never read.


person doberkofler    schedule 06.05.2021    source источник
comment
В этом случае нельзя использовать React.FC. typescriptlang.org/play?#code/   -  person Aleksey L.    schedule 06.05.2021
comment
@AlekseyL. Я считаю, тебе следует написать ответ   -  person captain-yossarian    schedule 06.05.2021
comment
@ captain-yossarian В вопросе используется требование React.FC, поэтому я не публикую это как ответ   -  person Aleksey L.    schedule 06.05.2021
comment
@AlekseyL. Я все еще немного запутался. Похоже, что проблема синтаксическая и вызвана использованием функции стрелки вместо объявления функции. Это ограничение TypeScript? Я также не очень понимаю параметр универсального типа <keyType extends { toString(): string } = string>. Не могли бы вы подробнее рассказать о { toString(): string }?   -  person doberkofler    schedule 06.05.2021
comment
Что касается extends { toString(): string } - это ограничение параметра универсального типа, поэтому предоставленный тип должен иметь toString метод (вы делаете id.toString() внутри функции). Что касается стрелочной функции: если вы используете React.FC, вы не можете оставить параметр универсального типа открытым (предоставляется потребителем)   -  person Aleksey L.    schedule 06.05.2021
comment
Вот пример определения компонента в качестве функции стрелки typescriptlang.org/play?#code/   -  person Aleksey L.    schedule 06.05.2021
comment
@doberkofler еще одна вещь - не уверен, зачем здесь нужны дженерики. Почему бы, например, не определить id: string | number?   -  person Aleksey L.    schedule 07.05.2021
comment
@AlekseyL. Вы абсолютно правы. Это надуманный пример только для того, чтобы максимально упростить его.   -  person doberkofler    schedule 07.05.2021


Ответы (2)


Я думаю, что это сусло, использующее здесь функцию более высокого порядка:

import React, { FC } from 'react';

type GenericPropsType<T = any> = {
    id: T,
    value: string,
};

const HoC = <T,>(): FC<GenericPropsType<T>> => (props) => <div></div>

const WithString = HoC<string>() // React.FC<GenericPropsType<string>>

Недостаток: накладные расходы на функции возникают только из-за типа

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

const HoC = <T,>(a:T): FC<GenericPropsType<T>> => (props) => <div></div>

const WithString = HoC('a') // React.FC<GenericPropsType<string>>

В противном случае я предлагаю вам использовать душу @Aleksey L.

person captain-yossarian    schedule 06.05.2021

Основываясь на объяснении @Aleksey L., я пришел к следующему полному примеру, что nthzat может быть полезен другим:

import React from 'react';
import ReactDOM from 'react-dom';

type GenericPropsType<keyType> = {
  id: keyType,
    value: string,
};

const GenericElement = <keyType extends string | number = string>({
  id,
  value = ''
}: GenericPropsType<keyType>): JSX.Element => {
    return (<div>{id}={value}</div>);
};

const UseGenericElement: React.FC = () => {
  return (<div><GenericElement id={4711} value="4711" /></div>);
};

ReactDOM.render(
  <div><UseGenericElement /></div>,
  document.getElementById('root')
);
person doberkofler    schedule 06.05.2021