reactjs - Typescript & React-komponent som aksepterer onChange for både TextArea og Input
Jeg er ny på TypeScript og jeg prøver å lage en input-komponent som, hvis den mottar type="text", gjengir en input, og hvis den mottar type="textarea", gjengir, som du skjønner, en textarea. Problemet er at TypeScript klager når jeg bruker komponenten i koden min sammen med en onChange, det virker som om den ikke lar meg bruke to typer på samme hendelse?
Det viser meg:
Type '(e: ChangeEvent<HTMLInputElement>) => void' is not assignable to type '(e?: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement> | undefined) => void'.
Types of parameters 'e' and 'e' are incompatible.
Type 'ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement> | undefined' is not assignable to type 'ChangeEvent<HTMLInputElement>'.
Type 'undefined' is not assignable to type 'ChangeEvent<HTMLInputElement>'.
input.js
interface InputProps {
className?: string;
type?: string;
placeholder?: string;
onChange?: (e?: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
}
const Input: FunctionComponent<InputProps> = ({ type = 'text', ...props }) => {
if (type === 'textarea') {
return <textarea {...props} />;
}
return <input type={type} {...props} />;
};
bruk:
class Usage extends React.Component<State> {
state: State;
onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ input: e.target.value });
};
render() {
return (
<Input placeholder="Write an something..." onChange={this.onInputChange} />
);
}
}
Hvordan kan jeg fikse det?
OPPDATERING
Måten jeg løste det på for øyeblikket er ved å si at event kan være av typen any, men det er slags en snarvei
type CommonProps = {
className?: string;
placeholder?: string;
type?: string;
onChange?: (e: any) => void;
};
Svar #1
Du kan bruke en diskriminert union for å sende inn to typer argumenter, en for text og den andre for textarea. Dette har den ekstra fordelen av å sikre at håndtereren og typen er i synk.
type InputProps = { // The common Part
className?: string;
placeholder?: string;
} & ({ // The discriminated union
type?: "text";
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
} | {
type: "textarea";
onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
})
const Input: FunctionComponent<InputProps> = (props: InputProps) => {
if (props.type === 'textarea') {
return <textarea {...props} />;
}
return <input {...props} />;
};
class Usage extends React.Component<State> {
state: State;
onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ input: e.target.value });
};
render() {
return (
<Input placeholder="Write an something..." onChange={this.onInputChange} />
);
}
}
Svar #2
Du må opprette en klasse i tilfelle du bruker TypeScript. Den vanlige funksjonen tillater ikke | i TypeScript-egenskapstypene.
Dette bør være din Input.js-fil:
export interface IInputProps {
className?: string;
type?: string;
placeholder?: string;
onChange?: (e?: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
}
export class Input extends React.Component<IInputProps, {}> {
constructor(props: IInputProps) {
super(props);
}
render() {
const { props, props: { type } } = this;
if (type === 'textarea') {
return <textarea {...props} />;
}
return <input type={type} {...props} />;
}
}
og her er hvordan det kan brukes:
class Usage extends React.Component<State> {
state: State;
onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ input: e.target.value });
};
render() {
return (
<Input placeholder="Write an something..." onChange={this.onInputChange} />
);
}
}
Slik vil det vurdere om det er en Input eller en TextArea:
