Recipes
›
Chapter 10: TypeScript and React
Writing Controlled Components
Recipe 10.8 from
The TypeScript Cookbook
import React, { useState } from "react";
type OnlyRequired<T, K extends keyof T = keyof T> = Required<Pick<T, K>> &
Partial<Omit<T, K>>;
type ControlledProps = OnlyRequired<
JSX.IntrinsicElements["input"],
"value" | "onChange"
> & {
defaultValue?: never;
};
type UncontrolledProps = Omit<
JSX.IntrinsicElements["input"],
"value" | "onChange"
> & {
defaultValue: string;
value?: never;
onChange?: never;
};
type InputProps = ControlledProps | UncontrolledProps;
function Input({ ...allProps }: InputProps) {
return <input {...allProps} />;
}
function Controlled() {
const [val, setVal] = useState("");
return <Input value={val} onChange={(e) => setVal(e.target.value)} />;
}
function Uncontrolled() {
return <Input defaultValue="Hello" />;
}