Skip to content

Commit

Permalink
Feat(Select, DatePicker): add type to catch unsupported props (#6667)
Browse files Browse the repository at this point in the history
В тех местах, где при определённых условиях под капотом используется нативный компонент, мы, бывает, забываем исключать новые свойства необходимые только в кастомных компонентах. В итоге неспользуемые свойства оказываются в DOM. (#6663, #6386).

Добавил тип, как посоветовал @inomdzhon в #6663 (comment), чтобы при добавлении нового свойства линтер ругался если для нативного компонента это свойство не нужно.
  • Loading branch information
mendrew authored and actions-user committed Mar 12, 2024
1 parent 467d0e0 commit 1d30002
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
7 changes: 4 additions & 3 deletions packages/vkui/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as React from 'react';
import { leadingZero } from '@vkontakte/vkjs';
import { range } from '../../helpers/range';
import { useAdaptivityHasPointer } from '../../hooks/useAdaptivityHasPointer';
import { HTMLAttributesWithRootRef } from '../../types';
import { HasOnlyExpectedProps, HTMLAttributesWithRootRef } from '../../types';
import { CustomSelect } from '../CustomSelect/CustomSelect';
import { Input } from '../Input/Input';
import { Input, type InputProps } from '../Input/Input';
import { RootComponent } from '../RootComponent/RootComponent';
import styles from './DatePicker.module.css';

Expand Down Expand Up @@ -167,9 +167,10 @@ const DatePickerNative = ({
},
[onDateChange],
);
const inputProps: HasOnlyExpectedProps<typeof restProps, InputProps> = restProps;
return (
<Input
{...restProps}
{...inputProps}
type="date"
onChange={onStringChange}
min={convertToInputFormat(min)}
Expand Down
11 changes: 7 additions & 4 deletions packages/vkui/src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as React from 'react';
import { useAdaptivityHasPointer } from '../../hooks/useAdaptivityHasPointer';
import { HasOnlyExpectedProps } from '../../types';
import {
CustomSelect,
type CustomSelectOptionInterface,
type SelectProps,
} from '../CustomSelect/CustomSelect';
import { NativeSelect } from '../NativeSelect/NativeSelect';

import { NativeSelect, type NativeSelectProps } from '../NativeSelect/NativeSelect';
export type SelectType = 'default' | 'plain' | 'accent';

/**
Expand Down Expand Up @@ -35,17 +35,20 @@ export const Select = <OptionT extends CustomSelectOptionInterface>({
dropdownOffsetDistance,
dropdownAutoWidth,
forceDropdownPortal,
selectType,
noMaxHeight,
autoHideScrollbar,
autoHideScrollbarDelay,
labelTextTestId,
nativeSelectTestId,
...nativeProps // TODO: https://github.com/Microsoft/TypeScript/issues/12936
after,
mode,
...restProps
} = props;

const hasPointer = useAdaptivityHasPointer();

const nativeProps: HasOnlyExpectedProps<typeof restProps, NativeSelectProps> = restProps;

return (
<React.Fragment>
{(hasPointer === undefined || hasPointer) && <CustomSelect {...props} />}
Expand Down
37 changes: 37 additions & 0 deletions packages/vkui/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,40 @@ export type GetPropsWithFunctionKeys<T> = {
}[keyof T];

export type PickOnlyFunctionProps<T> = Pick<T, GetPropsWithFunctionKeys<T>>;

/**
* Даёт возможность поймать ошибку, если в компонент передаются лишние свойства.
*
* @example
* // пример использования
* const nativeProps: HasOnlyExpectedProps<typeof restProps, NativeSelectProps> = restProps;
*
* @example
* // расширенный пример
* type SelectProps {
* mode: string,
* multiline: boolean;
* selectType?: SelectType;
* }
*
* type NativeSelectProps {
* selectType?: SelectType;
* }
*
* const selectProps: SelectProps = {
* mode: "card",
* multiline: true,
* selectType: "default",
* }
*
* // будет ошибка, так как multiline в NativeSelectProps нет
* const {mode, ...restProps} = selectProps;
* const nativeProps: HasOnlyExpectedProps<typeof restProps, NativeSelectProps> = restProps;
*
* // а вот так ошибки не будет, так как restProps больше не содержит multiline
* const {mode, multiline, ...restProps} = selectProps;
* const nativeProps: HasOnlyExpectedProps<typeof restProps, NativeSelectProps> = restProps;
*/
export type HasOnlyExpectedProps<Props, ExpectedProps> = {
[K in keyof Props]: K extends keyof ExpectedProps ? ExpectedProps[K] : never;
};

0 comments on commit 1d30002

Please sign in to comment.