Reputation: 21
I'm trying to define a generic type based on the type of a prop. The implementation looks something like
interface ChildrenProps<T> {
values: T;
errors: T;
}
interface FormHandlerProps<T> {
initialValues: T;
children: React.FC<ChildrenProps<T>>;
}
export function FormHandler<T>({
children,
initialValues,
}: FormHandlerProps<typeof initialValues>) {
const [values] = useState<typeof initialValues>(initialValues)
return(
<>
children({values})
</>
)
}
However when I implement as below, 'values' is defined as 'any'
<FormHandler
initialValues={{name: 'test', address: 'test'}}
>
{({values}) => (
<p> {values.name} </p>
<p> {values.address} </p>
<p> {values.foobar} </p> // SHOULD BE INVALID
)}
</FormHandler>
Upvotes: 0
Views: 45
Reputation: 328262
You can't define the type of initialValues
in terms of typeof initialValues
; the compiler sees that as circular and doesn't know what to do. It bails out by giving it the any
type:
export function FormHandler<T>({
children, initialValues
// -----> ~~~~~~~~~~~~~
// 'initialValues' implicitly has type 'any' because it does not have a type
// annotation and is referenced directly or indirectly in its own initializer.
}: FormHandlerProps<typeof initialValues>) { /* ... */ }
You should have seen a compiler warning to this effect as shown above, assuming you are using the --noImplicitAny
or --strict
compiler options. If you're not, you really should consider it, since it does a good job of catching errors.
Anyway, the fix here is to just give the argument an explicit type that is not self-referential:
export function FormHandler<T>({
children, initialValues
}: FormHandlerProps<T>) {
const [values] = useState<typeof initialValues>(initialValues)
return (
<>
children({values})
</>
)
}
And then the rest of your code should hopefully work as expected.
Upvotes: 2