Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Typescript: FunctionComponent with templated props

I have a component with templated props:

const MyComponent = <Value extends any>({ value }: MyComponentProps<Value>) => <div />;

Which I can use without explicitly specifying the type of Value (it is inferred):

<MyComponent value="1" />
<MyComponent value={1} />

I usually write my components this way:

const MyComponent: FunctionComponent<MyComponentProps> = ({ value }) => <div />;

But haven't found a way to template MyComponent and MyComponentProps with this syntax... Does anyone know how to do it? Thanks in advance!

like image 815
adrienharnay Avatar asked Jan 20 '26 06:01

adrienharnay


1 Answers

Based on your comment you just want this:

interface MyComponentProps<V> {
    views: V;
    initialView: keyof V;
}

type KeyedFunctionComponent<T> = FunctionComponent<MyComponentProps<T>>;

const MyComponent: KeyedFunctionComponent<Views> = (views, initialViews) => <div />;

Then declare your function component using either an interface or "typeof views" as the generic argument. Which is good I think. But, what you really want is this combined with a generator, which will allow you to bind and template correctly:

// Declare some views constant:
const views = { home: "home", index: "index" };


// Declare a type for our bound views component
interface KeyedProps<V> {
    initialView?: keyof V;
}


// declare a type for our input function
interface KeyedWithViewsProps<V> extends KeyedProps<V> {
    views: V;
}


// This is the binding function itself
function createKeyedComponent<T>(views: T, toWrap: FunctionComponent<KeyedWithViewsProps<T>>): FunctionComponent<KeyedProps<T>> {
    return (props: KeyedProps<T>) => toWrap({views, initialView: props.initialView});
}


// Call the binder, and pass in the function we want to bind.
const MyComponent = createKeyedCompnonet(views, () => <div />);

// Now, using the component, only requires the optional initialView param, and it it type-checked to ensure it is a member of views
<MyComponent initialView="home" /> // works
<MyComponent initialView="other" /> // doesn't work


like image 114
nileshp87 Avatar answered Jan 22 '26 19:01

nileshp87



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!