From 1d30002d2e2ddc63c56326d5a2fdd169b9ea108d Mon Sep 17 00:00:00 2001 From: Andrey Medvedev Date: Tue, 12 Mar 2024 12:22:17 +0300 Subject: [PATCH] Feat(Select, DatePicker): add type to catch unsupported props (#6667) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В тех местах, где при определённых условиях под капотом используется нативный компонент, мы, бывает, забываем исключать новые свойства необходимые только в кастомных компонентах. В итоге неспользуемые свойства оказываются в DOM. (#6663, #6386). Добавил тип, как посоветовал @inomdzhon в #6663 (comment), чтобы при добавлении нового свойства линтер ругался если для нативного компонента это свойство не нужно. --- .../src/components/DatePicker/DatePicker.tsx | 7 ++-- .../vkui/src/components/Select/Select.tsx | 11 ++++-- packages/vkui/src/types.ts | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/vkui/src/components/DatePicker/DatePicker.tsx b/packages/vkui/src/components/DatePicker/DatePicker.tsx index bb96371991..47cda2a9c2 100644 --- a/packages/vkui/src/components/DatePicker/DatePicker.tsx +++ b/packages/vkui/src/components/DatePicker/DatePicker.tsx @@ -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'; @@ -167,9 +167,10 @@ const DatePickerNative = ({ }, [onDateChange], ); + const inputProps: HasOnlyExpectedProps = restProps; return ( ({ 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 = restProps; + return ( {(hasPointer === undefined || hasPointer) && } diff --git a/packages/vkui/src/types.ts b/packages/vkui/src/types.ts index deba74d767..8be598ae14 100644 --- a/packages/vkui/src/types.ts +++ b/packages/vkui/src/types.ts @@ -89,3 +89,40 @@ export type GetPropsWithFunctionKeys = { }[keyof T]; export type PickOnlyFunctionProps = Pick>; + +/** + * Даёт возможность поймать ошибку, если в компонент передаются лишние свойства. + * + * @example + * // пример использования + * const nativeProps: HasOnlyExpectedProps = 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 = restProps; + * + * // а вот так ошибки не будет, так как restProps больше не содержит multiline + * const {mode, multiline, ...restProps} = selectProps; + * const nativeProps: HasOnlyExpectedProps = restProps; + */ +export type HasOnlyExpectedProps = { + [K in keyof Props]: K extends keyof ExpectedProps ? ExpectedProps[K] : never; +};