Skip to content

Instantly share code, notes, and snippets.

@a1300
Created June 1, 2025 15:15
Show Gist options
  • Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
svg
@a1300
Copy link
Author

a1300 commented Jul 13, 2025

@a1300
Copy link
Author

a1300 commented Jul 18, 2025

@a1300
Copy link
Author

a1300 commented Jul 18, 2025

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

To type a generic ReactNode that guarantees a className prop, you’ll want to constrain the type to a React element that accepts props — particularly one that includes className. A plain ReactNode is too flexible (it can be a string, fragment, boolean, etc.), so you’ll need a more refined approach.

Here’s a pattern that works well:

import React, { ReactElement, ComponentType } from 'react';

type WithClassNameProps = {
  className?: string;
};

type Props<T extends ComponentType<WithClassNameProps>> = {
  Component: T;
};

// Example usage
const Wrapper = <T extends ComponentType<WithClassNameProps>>({
  Component,
}: Props<T>) => {
  return <Component className="my-class" />;
};

🔍 What’s happening here:

  • ComponentType<P> is a generic for a React component that accepts props of type P.
  • We're restricting it with WithClassNameProps so we know for sure it accepts className.
  • This ensures your passed-in Component (like a div, button, or custom component) will support the className prop at type level.

If you’re passing an actual element (like <div />) rather than a component reference, you’d use ReactElement<WithClassNameProps> instead.

Would you like an example with JSX-style children too? Or maybe you want to extend the prop checks even further?

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

React.cloneElement is a powerful—but often misunderstood—tool in React’s arsenal. It lets you create a new React element based on an existing one, while overriding or adding props and children. Here's why and when you'd use it:

🧩 Why Use React.cloneElement()

  • Inject props into children: Useful when a parent component needs to modify or extend its children without changing their original implementation.
  • Enhance reusability: You can build flexible, reusable UI components by dynamically customizing child elements.
  • Avoid prop drilling: Instead of passing props through multiple layers, cloneElement lets you inject them directly.

📦 Common Use Cases

  • Customizing child components:

    const cloned = React.cloneElement(<Button />, { color: 'red' });

    This creates a new <Button /> with the color prop set to 'red'.

  • Dynamic rendering in lists:

    React.Children.map(children, (child, index) =>
      React.cloneElement(child, { isActive: index === selectedIndex })
    );

    This is handy for components like tabs or selectable lists.

  • Wrapping components with additional behavior:
    For example, adding event handlers or styling to children passed into a container.

⚠️ Caveats

  • Can make code harder to trace: Since props are injected dynamically, it’s not always obvious where they come from.
  • Not ideal for static typing: TypeScript may struggle with inferred props when using cloneElement.
  • Better alternatives often exist: Consider using render props, context, or custom hooks for clearer data flow.

Would you like to see a real-world example or explore alternatives like render props or context?

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

@a1300
Copy link
Author

a1300 commented Jul 20, 2025

@a1300
Copy link
Author

a1300 commented Aug 2, 2025

``
const [selection, setSelection] = useState({ state: {}, items: [] });

const table = useReactTable({
data,
columns,
getRowId: row => row.id,
state: { rowSelection: selection.state },
onRowSelectionChange: updater => {
const newState = updater(selection.state);
const selectedItems = data.filter(item => newState[item.id]);
setSelection({ state: newState, items: selectedItems });
},
});

@a1300
Copy link
Author

a1300 commented Aug 4, 2025

@a1300
Copy link
Author

a1300 commented Sep 7, 2025

@a1300
Copy link
Author

a1300 commented Sep 11, 2025

type OnlyArrays<T> = {
    [K in keyof T]: T[K] extends any[] ? K : never
}[keyof T]

type ArrayItemType<T> = T extends (infer U)[] ? U : never;

function access<
    T extends object,
    K extends OnlyArrays<T>,
    A extends (a: ArrayItemType<T[K]>) => boolean
>
    (first: T, key: K, func: A): {
        added: Array<ArrayItemType<T[K]>>
         
    } {
        const added = (first[key] as Array<ArrayItemType<T[K]>>).filter(func)

        return {
            added,
        }
}

access(obj, "addresses", (a) => true);

improvement

function access<
  T extends Record<K, any[]>,
  K extends keyof T,
  A extends (a: ArrayItemType<T[K]>) => boolean
>(
  first: T,
  key: K,
  func: A
): {
  added: ArrayItemType<T[K]>[]
} {
  const added = first[key].filter(func);
  return { added };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment