Skip to content

Commit

Permalink
Upgrade Typescript to 4.5.3 to match Kibana (#5591)
Browse files Browse the repository at this point in the history
* Upgrade typescript to 4.5.3

- to match Kibana

* Fix typescript err TS2339

Property 'MSInputMethodContext' does not exist on type 'Window & typeof globalThis'

* Fix typescript error TS2783

Error: 'onClick' is specified more than once, so this usage will be overwritten.

* Fix typescript errors TS2525 and TS7031

Errors:
- Initializer provides no value for this binding element and the binding element has no default value.
- Binding element '_onClick' implicitly has an 'any' type.

Fixes:
- Fix primary type issue, which was using `...` instead of `|| {}`
- Remove unnecessary `_onClick` cast
- Optional switch to optional chaining instead of && check

* Fix typescript error TS2774

Error:
- This condition will always return true since this function is always defined. Did you mean to call it instead?

Fix:
- [EuiPinnableListGroup] Remove unnecessary check, pinnable serves that purpose
- [EuiOverlayMask] Remove unnecessary check, there's already an early return at the beginning of the block
- [extra] DRY out portalTarget var - it's being used interchangably with overlayMaskNode.current

* Fix catch error types (TS2571 & TS2345)

Errors:
- Object is of type 'unknown'.
- Type 'unknown' is not assignable to type 'EuiMarkdownParseError | null'

see https://stackoverflow.com/questions/68240884/error-object-inside-catch-is-of-type-unkown

We could optionally disable `useUnknownInCatchVariables`, but I think it also does make sense to check for a valid Error instance if we're going to dive into it.

* Update typescript related dependencies

* Changelog

* Update reactElementTypeExpanded replacement

- it appears to have changed as of the recent upgrade, this keeps all props that output `ReactElement` the same as before

* Expand string enums that are used within unions

- Was previously working, with, e.g. `number | SomeStringEnum`, now needs a config to restore functionality

* Revert shouldExtractValuesFromUnion

- it's causing too many other unintended side effects (like turning `|`s into `,`s. There's probably no working around `number | SomeStringEnum` without stating the enum, it'll have to be a props doc changing going forward

* Table auto props docs - spell out direction explicitly

- enum no longer appears to be extracted by react-docgen

* Fix other reactNodeTypeExpanded replace

- appears to have also changed/shortened since the upgrade

* Convert reactNodeTypeExpanded to a regex

It appears as
```
string | number | boolean | {} | ReactElement | ReactNodeArray | ReactPortal
```
in some places, and
```
string | number | boolean | {} | ReactElement | ReactNodeArray | ReactPortal | ({} & string) | (ReactElement<...> & string) | (ReactNodeArray & string) | (ReactPortal & string)
```
in others - this regex should capture both scenarios

* Portal auto props docs - spell out position explicitly

- string enums within objects no longer appear to be expanded

* Fix broken EuiButton props table

- EuiButtonDisplay was bogarting the docgenInfo for the file, apparently - moving its declaration below EuiButton and giving EuiButton its a displayName seems to be required to get its docgenInfo working

* Improve react-docgen-typescript wiki docs

- Add warning about displayName bug found in dede73b#r799165839

- useful links to our custom react-docgen config/filters + react's docs

- lint misc typos/grammar
  • Loading branch information
Constance authored Feb 7, 2022
1 parent 27681eb commit aa4cfd7
Show file tree
Hide file tree
Showing 17 changed files with 353 additions and 187 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
- Fixed `EuiInMemoryTable`'s `onTableChange` callback not returning the correct `sort.field` value on pagination ([#5588](https://github.com/elastic/eui/pull/5588))
- Fixed `EuiFilePicker` allowing files to be removed when `disabled` ([#5603](https://github.com/elastic/eui/pull/5603))

**Breaking changes**

- Upgraded TypeScript version to ~4.5.3 ([#5591](https://github.com/elastic/eui/pull/5591))

## [`46.2.0`](https://github.com/elastic/eui/tree/v46.2.0)

- Updated `EuiDataGrid`s with scrolling content to always have a border around the grid body and any scrollbars ([#5563](https://github.com/elastic/eui/pull/5563))
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"@babel/plugin-transform-runtime": "^7.11.0",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@babel/preset-typescript": "^7.12.1",
"@babel/preset-typescript": "^7.16.7",
"@cypress/code-coverage": "^3.9.12",
"@cypress/react": "^5.10.3",
"@cypress/webpack-dev-server": "^1.7.0",
Expand All @@ -132,8 +132,8 @@
"@types/tabbable": "^3.1.0",
"@types/url-parse": "^1.4.3",
"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "^5.10.0",
"@typescript-eslint/parser": "^5.10.0",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"argparse": "^2.0.1",
"autoprefixer": "^9.8.6",
"axe-core": "^4.1.1",
Expand Down Expand Up @@ -205,7 +205,7 @@
"puppeteer": "^5.5.0",
"raw-loader": "^4.0.1",
"react": "^16.12.0",
"react-docgen-typescript": "^1.20.5",
"react-docgen-typescript": "^2.2.2",
"react-dom": "^16.12.0",
"react-helmet": "^6.1.0",
"react-redux": "^7.2.1",
Expand All @@ -228,7 +228,7 @@
"start-server-and-test": "^1.11.3",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^4.1.0",
"typescript": "4.1.3",
"typescript": "4.5.3",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.0",
"webpack": "^4.46.0",
Expand All @@ -247,6 +247,6 @@
"prop-types": "^15.5.0",
"react": "^16.12",
"react-dom": "^16.12",
"typescript": "~4.1.3"
"typescript": "~4.5.3"
}
}
5 changes: 2 additions & 3 deletions scripts/babel/react-docgen-typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ const intrinsicValuesRaw = [
* Replace ReactElement and ReactNode expanded types with ReactElement and ReactNode
*/
const reactElementTypeExpanded =
'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)>) | (new (props: any) => Component<any, any, any>)>';
'ReactElement<any, string | JSXElementConstructor<any>>';

const reactNodeTypeExpanded =
'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)>) | (new (props: any) => Component<...>)> | ... 5 more ... | (ReactPortal & string)';
const reactNodeTypeExpanded = /(string \| number \| boolean \| {} \| ReactElement \| ReactNodeArray \| ReactPortal)( \| \({} & string\).+\(ReactPortal & string\))?/g;
2 changes: 1 addition & 1 deletion src-docs/src/components/guide_section/guide_section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export const GuideSection: FunctionComponent<GuideSection> = ({
const isPlaygroundUnsupported =
typeof window !== 'undefined' &&
typeof document !== 'undefined' &&
!!window.MSInputMethodContext &&
!!(window as any).MSInputMethodContext &&
// @ts-ignore doesn't exist?
!!document.documentMode;

Expand Down
2 changes: 1 addition & 1 deletion src/components/basic_table/basic_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export interface Criteria<T> {
*/
sort?: {
field: keyof T;
direction: Direction;
direction: 'asc' | 'desc';
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/components/basic_table/table_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { ReactElement, ReactNode, TdHTMLAttributes } from 'react';
import { Direction, HorizontalAlignment } from '../../services';
import { HorizontalAlignment } from '../../services';
import { Pagination } from './pagination_bar';
import { Action } from './action_types';
import { Primitive } from '../../services/sort/comparators';
Expand Down Expand Up @@ -147,7 +147,7 @@ export interface EuiTableSortingType<T> {
*/
sort?: {
field: keyof T;
direction: Direction;
direction: 'asc' | 'desc';
};
/**
* Enables/disables unsorting of table columns. Supported by EuiInMemoryTable.
Expand Down
160 changes: 82 additions & 78 deletions src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,82 @@ export interface EuiButtonProps extends EuiButtonContentProps, CommonProps {
style?: CSSProperties;
}

export type EuiButtonPropsForAnchor = PropsForAnchor<
EuiButtonProps,
{
buttonRef?: Ref<HTMLAnchorElement>;
}
>;

export type EuiButtonPropsForButton = PropsForButton<
EuiButtonProps,
{
buttonRef?: Ref<HTMLButtonElement>;
}
>;

export type Props = ExclusiveUnion<
EuiButtonPropsForAnchor,
EuiButtonPropsForButton
>;

/**
* EuiButton is largely responsible for providing relevant props
* and the logic for element-specific attributes
*/
export const EuiButton: FunctionComponent<Props> = ({
isDisabled: _isDisabled,
disabled: _disabled,
href,
target,
rel,
type = 'button',
buttonRef,
...rest
}) => {
const isHrefValid = !href || validateHref(href);
const disabled = _disabled || !isHrefValid;
const isDisabled = _isDisabled || !isHrefValid;

const buttonIsDisabled = rest.isLoading || isDisabled || disabled;
const element = href && !isDisabled ? 'a' : 'button';

let elementProps = {};
// Props for all elements
elementProps = { ...elementProps, isDisabled: buttonIsDisabled };
// Element-specific attributes
if (element === 'button') {
elementProps = { ...elementProps, disabled: buttonIsDisabled };
}

const relObj: {
rel?: string;
href?: string;
type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
target?: string;
} = {};

if (href && !buttonIsDisabled) {
relObj.href = href;
relObj.rel = getSecureRelForTarget({ href, target, rel });
relObj.target = target;
} else {
relObj.type = type as ButtonHTMLAttributes<HTMLButtonElement>['type'];
}

return (
<EuiButtonDisplay
element={element}
baseClassName="euiButton"
ref={buttonRef}
{...elementProps}
{...relObj}
{...rest}
/>
);
};
EuiButton.displayName = 'EuiButton';

export type EuiButtonDisplayProps = EuiButtonProps &
HTMLAttributes<HTMLElement> & {
/**
Expand All @@ -123,12 +199,13 @@ export type EuiButtonDisplayProps = EuiButtonProps &
};

/**
* *INTERNAL ONLY*
* Component for displaying any element as a button
* EuiButton is largely responsible for providing relevant props
* and the logic for element-specific attributes
* EuiButtonDisplay is an internal-only component used for displaying
* any element as a button.
* NOTE: This component *must* be below EuiButton in the file and
* EuiButton must also set a displayName for react-docgen-typescript
* to correctly set EuiButton's docgenInfo and display a props table.
*/
const EuiButtonDisplay = forwardRef<HTMLElement, EuiButtonDisplayProps>(
export const EuiButtonDisplay = forwardRef<HTMLElement, EuiButtonDisplayProps>(
(
{
element = 'button',
Expand Down Expand Up @@ -218,77 +295,4 @@ const EuiButtonDisplay = forwardRef<HTMLElement, EuiButtonDisplayProps>(
);
}
);

EuiButtonDisplay.displayName = 'EuiButtonDisplay';
export { EuiButtonDisplay };

export type EuiButtonPropsForAnchor = PropsForAnchor<
EuiButtonProps,
{
buttonRef?: Ref<HTMLAnchorElement>;
}
>;

export type EuiButtonPropsForButton = PropsForButton<
EuiButtonProps,
{
buttonRef?: Ref<HTMLButtonElement>;
}
>;

export type Props = ExclusiveUnion<
EuiButtonPropsForAnchor,
EuiButtonPropsForButton
>;

export const EuiButton: FunctionComponent<Props> = ({
isDisabled: _isDisabled,
disabled: _disabled,
href,
target,
rel,
type = 'button',
buttonRef,
...rest
}) => {
const isHrefValid = !href || validateHref(href);
const disabled = _disabled || !isHrefValid;
const isDisabled = _isDisabled || !isHrefValid;

const buttonIsDisabled = rest.isLoading || isDisabled || disabled;
const element = href && !isDisabled ? 'a' : 'button';

let elementProps = {};
// Props for all elements
elementProps = { ...elementProps, isDisabled: buttonIsDisabled };
// Element-specific attributes
if (element === 'button') {
elementProps = { ...elementProps, disabled: buttonIsDisabled };
}

const relObj: {
rel?: string;
href?: string;
type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
target?: string;
} = {};

if (href && !buttonIsDisabled) {
relObj.href = href;
relObj.rel = getSecureRelForTarget({ href, target, rel });
relObj.target = target;
} else {
relObj.type = type as ButtonHTMLAttributes<HTMLButtonElement>['type'];
}

return (
<EuiButtonDisplay
element={element}
baseClassName="euiButton"
ref={buttonRef}
{...elementProps}
{...relObj}
{...rest}
/>
);
};
7 changes: 3 additions & 4 deletions src/components/header/header_links/header_links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,15 @@ export const EuiHeaderLinks: FunctionComponent<EuiHeaderLinksProps> = ({
popoverProps,
...rest
}) => {
const { onClick: _onClick, iconType = 'apps', ...popoverButtonRest } = {
...popoverButtonProps,
};
const { onClick, iconType = 'apps', ...popoverButtonRest } =
popoverButtonProps || {};

const [mobileMenuIsOpen, setMobileMenuIsOpen] = useState(false);

const onMenuButtonClick: MouseEventHandler<
HTMLButtonElement & HTMLAnchorElement
> = (e) => {
_onClick && _onClick(e);
onClick?.(e);
setMobileMenuIsOpen(!mobileMenuIsOpen);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const EuiPinnableListGroup: FunctionComponent<EuiPinnableListGroupProps>
);

// Add the pinning action unless the item has it's own extra action
if (onPinClick && !itemProps.extraAction && pinnable) {
if (pinnable && !itemProps.extraAction) {
// Different displays for pinned vs unpinned
if (pinned) {
itemProps.extraAction = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/markdown_editor/markdown_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export const EuiMarkdownEditor = forwardRef<
const parsed = parser.processSync(value);
return [parsed, null];
} catch (e) {
return [null, e];
return [null, e as EuiMarkdownParseError];
}
}, [parser, value]);

Expand Down
11 changes: 5 additions & 6 deletions src/components/overlay_mask/overlay_mask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,18 @@ export const EuiOverlayMask: FunctionComponent<EuiOverlayMaskProps> = ({
}, [className, headerZindexLocation]);

useEffect(() => {
if (!overlayMaskNode.current || !onClick) return;
const portalTarget = overlayMaskNode.current;
if (!portalTarget || !onClick) return;

const listener = (e: Event) => {
if (e.target === overlayMaskNode.current) {
if (e.target === portalTarget) {
onClick();
}
};
overlayMaskNode.current.addEventListener('click', listener);
portalTarget.addEventListener('click', listener);

return () => {
if (portalTarget && onClick) {
portalTarget.removeEventListener('click', listener);
}
portalTarget.removeEventListener('click', listener);
};
}, [onClick]);

Expand Down
6 changes: 3 additions & 3 deletions src/components/portal/portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ export const insertPositions: InsertPositionsMap = {
before: 'beforebegin',
};

type EuiPortalInsertPosition = keyof typeof insertPositions;

export const INSERT_POSITIONS: EuiPortalInsertPosition[] = keysOf(
insertPositions
);

type EuiPortalInsertPosition = keyof typeof insertPositions;

export interface EuiPortalProps {
/**
* ReactNode to render as this component's content
*/
children: ReactNode;
insert?: { sibling: HTMLElement; position: EuiPortalInsertPosition };
insert?: { sibling: HTMLElement; position: 'before' | 'after' };
portalRef?: (ref: HTMLDivElement | null) => void;
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/search_bar/query/default_syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,9 @@ const validateFieldValue = (
try {
schemaField.validate(value);
} catch (e) {
const message = e instanceof Error ? e.message : e;
error(
`Invalid value \`${expression}\` set for field \`${field}\` - ${e.message}`,
`Invalid value \`${expression}\` set for field \`${field}\` - ${message}`,
location
);
}
Expand Down
5 changes: 4 additions & 1 deletion src/components/search_bar/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ export class EuiSearchBar extends Component<EuiSearchBarProps, State> {
this.notifyControllingParent({ query, queryText, error: null });
this.setState({ query, queryText, error: null });
} catch (e) {
const error: Error = { name: e.name, message: e.message };
const error: Error =
e instanceof Error
? { name: e.name, message: e.message }
: { name: 'Unexpected error', message: String(e) };
this.notifyControllingParent({ query: null, queryText, error });
this.setState({ queryText, error });
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/suggest/suggest_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export const EuiSuggestItem: FunctionComponent<EuiSuggestItemProps> = ({
<button
onClick={onClick}
className={classes}
{...(rest as PropsForButton)}
{...(rest as Omit<PropsForButton, 'onClick' | 'className'>)}
>
{innerContent}
</button>
Expand Down
Loading

0 comments on commit aa4cfd7

Please sign in to comment.