简体   繁体   中英

Inferred Generic Type on React Component

Typescript is pretty good about inferred generic types. For example, if I write the following code:

class AwesomeClass<T> {
    constructor(public val: T) {
        // ...
    }

    public getVal(): T {
        return this.val;
    }
}

const inst = new AwesomeClass("Hello World");
const result = inst.getVal();

result is automatically typed to string . Nifty! I'd like to take that a step further with React.

If I make the follow component

interface IProps<T> {
    value: T;
    onClick: (result: T) => void;
}
interface IState { }

class AwesomeComponent<T> extends React.Component<IProps<T>, IState> {
    // ...
}

I'd really like it to be inferred that value has to have the same type as the result argument of onClick . Instead when I initialize the component with

<AwesomeComponent
    value="Hello World"
    onClick={(v) => { console.log(v); }} />;

I get a compile error error TS2322: Type 'string' is not assignable to type 'T' .

Is it possible to infer the generic type on a React element's props?

I realize that the JSX transpiles to a call to React.createElement (it doesn't directly initialize the class like I do with my AwesomeClass example above) and that this may complicate the process - is that a deal killer? If so, can I explicitly name a generic type using the JSX syntax?

This isn't possible yet, here's an issue about it: Using lookahead to detect generic JSX elements? .

For now what you'll need to do is:

interface IProps<T> {
    value: T;
    onClick: (result: T) => void;
}
interface IState { }

class AwesomeComponent<T> extends React.Component<IProps<T>, IState> {
    // ...
}

class ConcreteAwesomeComponent extends AwesomeComponent<string> {}

<ConcreteAwesomeComponent
    value="Hello World"
    onClick={(v) => { console.log(v); }} />;

for using functional component you can use this code


interface IMessagesProps<T> {
  data: T[];
  titleName: keyof T;
  type: MESSAGE_SYSTEM_TYPE;
}

const Messages = <T extends Record<keyof T, unknown>>(props: IMessagesProps<T>) => {
  const { data, type, titleName } = props;
  return (
    <>
      {data?.length ? (
        data.map((message, index) => {
           return (
            <div key={index}>
              <p >{message[titleName]}</p>
            </div>
          );
        })
      ) : (
        <div>Empty</div>
      )}
    </>
  );
};

export default Messages;

then you use Messages component like this :

interface IMarketNoticeResponse {
  id: string;
  message: string;
}

const messagesDisplayList : IMarketNoticeResponse[] = [
{id:"1",message:"message1"},
{id:"2",message:"message2"}]

<Messages<IMarketNoticeResponse>
      data={messagesDisplayList}
      titleName="message"
      type={messageType}
    />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM