Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
137 views
in Technique[技术] by (71.8m points)

javascript - React: TypeScript generics, auto switch parameter-type from function (function as props)

I would like to implement the following (in React/TypeScript (.tsx))

Main.tsx (edit: botCommands is an array in which multiple objects can be (with command and botResponse())

function Main() {
  return (
    <TestComponent
      botVariables={{
        tasks: [],
        groups: []
      }}
      botCommands={[
        {
          command: "-help",
          botResponse(botVariables) {
            return botVariables.tasks[0]
          }
        }
      ]}
    />
  );
}

TestComponent.tsx

interface BotCommand {
  command: string;
  botResponse(botVariables: any): string;
}

interface TestComponentProps {
  botVariables: any;
  botCommands: BotCommand[];
}

export default function TestComponent(props: TestComponentProps) {
  return (
    // magic
  );
}

in Main.tsx I would like that in the function botResponse() the type (currently any) is automatically adjusted. So that automatically the content of botVariables is taken as type.

Simply put, if I write in Main.tsx in the botResponse() function "botVariables." that tasks and groups can be suggested to me by the IDE. The data in botVariables can change so you can't just create an interface in the TestComponent.tsx file.

I tried with typescript generics but unfortunately failed. Thanks for help!

question from:https://stackoverflow.com/questions/65865011/react-typescript-generics-auto-switch-parameter-type-from-function-function-a

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If I am understanding your requirements correctly, botVariables could be anything, but the botVariables and the botCommands that we provide to the TestComponent need to match each other. That is, the arguments of the botResponse function in the botCommands are the same type as the botVariables prop.

In order to do this, we make the BotCommand interface generic, where the type T represents the type of the botResponse variables.

interface BotCommand<T> {
  command: string;
  botResponse(botVariables: T): string;
}

Our TestComponentProps are also generic, and we apply the same T to the botVariables as to the botCommands.

interface TestComponentProps<T> {
  botVariables: T;
  botCommands: BotCommand<T>[];
}

This means the component is generic as well.

export default function TestComponent<T>(props: TestComponentProps<T>) {...}

There is no problem creating a response from the passed variables, since both props share the same T.

export default function TestComponent<T>({ botVariables, botCommands }: TestComponentProps<T>) {
    return (
        <div>
            <h1>Bot Output</h1>
            {botCommands.map(command => (
                <div>
                    <div>Bot recieved command {command.command}</div>
                    <div>Bot responded {command.botResponse(botVariables)}</div>
                </div>
            ))}
        </div>
    );
}

You don't need to explicitly declare the generic T when you use the TestComponent because it can be inferred from the botVariables prop. If the botCommands don't match, typescript will complain.

In this example:

function Main() {
  return (
    <TestComponent
      botVariables={{
        tasks: ["first"],
        groups: ["something"]
      }}
      botCommands={[{
        command: "-help",
        botResponse(botVariables) {
          return botVariables.tasks[0]
        }
      }]}
    />
  );
}

The inferred signature for the botResponse function is complete and correct:

(method) BotCommand<{ tasks: string[]; groups: string[]; }>.botResponse(botVariables: {
    tasks: string[];
    groups: string[];
}): string

In order to get proper inference, I had to use ["first"] instead of an empty array because empty arrays are typed as never[] but we want string[]. You can use an empty array, but you would have to explicitly set the type for it.

Playground Link


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...