Skip to content

Instantly share code, notes, and snippets.

@cchaos
Last active March 24, 2021 16:24
Show Gist options
  • Select an option

  • Save cchaos/56d0bcfe0c4f4fb47148056bf1627b77 to your computer and use it in GitHub Desktop.

Select an option

Save cchaos/56d0bcfe0c4f4fb47148056bf1627b77 to your computer and use it in GitHub Desktop.
EUI: Restricted props with Typescript
import React from 'react';
import { ExclusiveUnion } from '../common';
/**
* 1. Use the EUI provided ExclusiveUnion to separate unique props.
*/
type _RestrictedProps = ExclusiveUnion<
{
/**
* 2. At least one of the unique props must be required, usually the one containing more options
*/
position: 'fixed';
/**
* 3. These next props are only available when `position` is `fixed`
*/
foo?: boolean;
bar?: boolean;
},
{
/**
* 4. These are the other options that can't be used in conjunction with the above props
*/
position?: 'static' | 'sticky';
}
>;
export interface EuiComponentProps
extends _RestrictedProps {
/**
* 5. Add all your other props that are allowed no matter the other configurations
*/
stuff?: string;
}
export const EuiComponent: FunctionComponent<EuiComponentProps> = ({
position = 'fixed',
foo = true,
bar = true,
stuff,
...rest
}) => {
/**
* 6. Still ensure the props values are correct for the particular configuration
*/
foo = position !== 'fixed' ? false : foo;
bar = position !== 'fixed' ? false : bar;
return ();
}
import React from 'react';
import { ExclusiveUnion } from '@elastic/eui';
export interface MyComponentProps {
/**
* 7. This component allows consumers to override defaults supplied to the resctricted component
*/
overrides?: EuiComponentProps;
}
export const MyComponent: FunctionComponent<MyComponentProps> = ({
overrides,
}) => {
return (
<EuiComponent
position="sticky"
// 8. Typescript will always complain, so using unknown here,
// but it won't restrict consumers from providing incompatible props, so ensure the EUI component handles that (see #6)
{...(overrides as unknown)}
/>
);
}
@cchaos
Copy link
Author

cchaos commented Mar 22, 2021

😕 It still likes to complain. Just differently...

Screen Shot 2021-03-22 at 18 37 25 PM

@thompsongl
Copy link

Try moving position="sticky" below the bottomBarProps spread

@cchaos
Copy link
Author

cchaos commented Mar 23, 2021

Unfortunately, no, it still doesn't work and also removes the ability for users to change that prop.

Screen Shot 2021-03-23 at 11 47 16 AM

In actuality, in this particular situation, I could omit those props, because they probably shouldn't be changing it, but it would be nice to have a workable solution for future components.

@chandlerprall
Copy link

At this location, https://github.com/cchaos/eui/blob/feat/bottom_bar_in_page/src/components/bottom_bar/bottom_bar.tsx#L52, the following change is needed: position?: 'fixed'; -> position: 'fixed'; (removed the ?)

Reason: When TS validates an incoming value against the two sides of a union, it looks for unique key definitions. As it is right now, the two sides for position are undefined | 'fixed' and undefined | 'sticky' | 'static', and because both share the undefined value it is not unique. This prevents the expected validation, and also confused TS when it tried to understand the shape of bottomBarProps.

Which opens up a second issue, where the Partial in bottomBarProps?: Partial<EuiBottomBarProps>; again removes that distinction by making adding undefined back to position: 'sticky'. In this specific case the fix is simple: bottomBarProps?: EuiBottomBarProps;. This works because every prop in EuiBottomBarProps is already optional - except for position when opting into usePortal or affordForDisplacement. We'll need to explore other approaches for the case where a component provides default or un-overridable values.

@cchaos
Copy link
Author

cchaos commented Mar 23, 2021

Haha, apparently this one is being super tricky. Everything that you just said works and makes sense. Except now when I want to JUST adjust the prop allowed when position="fixed". So this:

<EuiBottomBar usePortal={false} />

But, even though position="fixed" is the default, TS complains telling me I need to add it.

@cchaos
Copy link
Author

cchaos commented Mar 24, 2021

❤️ Thank you all for your help and input. I've updated this gist to exemplify both the "finalized" component and usage that we can link to in our EUI wiki.

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