Skip to content

Instantly share code, notes, and snippets.

@MrZhouZh
Last active March 8, 2024 02:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MrZhouZh/8e9f980af6d19f478607be48f371fea9 to your computer and use it in GitHub Desktop.
Save MrZhouZh/8e9f980af6d19f478607be48f371fea9 to your computer and use it in GitHub Desktop.
/**
* nested providers
* reference: https://x.com/mattpocockuk/status/1765780004040761395
* TS Playground: https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgKQMoA0CiAbApiXAOxgGEJCBnGKAVwGMZoAaOAJVwEMGA5CAE1xwAvnABmUCCDgAiKJwbSA3AChlMAJ5hBvAJKFRuKAB4AKgD44AXjgBtEwF07cXAA8YRPhTgdC6uAH44AAY4AC44AEZ7FTVNQTJiDmBKEgALYGw+OUIrRGU4ODp0zOz-cPYuGAA6Cp5+XBUhGNEaQgZgcjgABQkAN2ABKFQYLgBrI3zuvoHDL1d3Qk9bSYKEkeSKNIysoiYVuCrDtaSU4p3CG3tJq7MACgRJsGnBij2Cou3svaFwh4KniD9F6-fY2UZwZJwUa4dQQURTQEzKAUezhGz7ApoLB4AjEBJUWgMaBGHqIl5g+xmN4FGkAeRAwBgRl0+kMJOeswpVJkHxKRGkZn20UmTUmvPO5XkMF4AkaAEo8gU8PBCPVcuLsjECqJoHBbnRyFRbKSgYYWACwCi4HC4ADTciFX8aaqBLl2WTDIhDlULRQhGYEC7cEIjAB6E1IswqApCVQFOQwGhQHJBxqqAR0bAcORiVrtTomVL4XARwa3X0ggowIsEcLSPjZ0bSOAAHxk2GAAHNUjAlGKztlJZUalKZQ1lEI5eEsVUcMXiCoM1mcy02jAOjkAKoUQylwzliSWytwGg7qA6PjhQg0EAAI0M0cKA6IQ4YI8qY-l04ws5xRBgMShqGcAAEKYAAYrSrCYKopg1iWHJQHA1bFpY9aNgKkxGNuu6ISeZ4XpYCARAATAAzP6AASuDYNgEBwAA6tAmQAIRhjhUB7lAgphoWxZcVGqhAXAACC4EmJgrCwVxwxjI8iEUER6I0ssKkFHxBBcdSKlOmpyHwXWDZQE22k0kIpn2KZylqRxWkYoqen4YYF7hKRZGmTGFnUvYsaCgU1G0fRTFQKxyhhjJIx0KMglAA
*/
import type { JSXElementConstructor, ReactNode } from 'react';
type NoInfer<T> = [T][T extends any ? 0 : 1];
type ContainsChildren = {
children?: ReactNode;
};
function ProviderStack<
Providers extends [ContainsChildren, ...ContainsChildren[]],
>({
providers,
children,
}: {
providers: {
[k in keyof Providers]: [
JSXElementConstructor<Providers[k]>,
Omit<NoInfer<Providers[k]>, 'children'>,
];
};
children: ReactNode;
}) {
let node = children;
// eslint-disable-next-line no-restricted-syntax
for (const [Provider, props] of providers) {
node = <Provider {...props}>{node}</Provider>;
}
return node;
}
export default ProviderStack;
import type { ReactNode } from 'react';
declare function ThemeProvider(props: {
theme: 'dark' | 'light';
children: ReactNode;
}): JSX.Element;
declare function UserProvider(props: {
userInfo: { name: string };
children: ReactNode;
}): JSX.Element;
// Before
<ThemeProvider theme="light">
<UserProvider userInfo={{ name: 'xiaoming' }}>Hello World!</UserProvider>
</ThemeProvider>;
// After
<ProviderStack
providers={[
[
ThemeProvider,
{
theme: 'light',
},
],
[
UserProvider,
{
userInfo: {
name: 'xiaoming',
},
},
],
]}
>
Hello World!
</ProviderStack>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment