From bab8604e034ab33e5554bf301686d15d6292d1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=9A=D1=80?= =?UTF-8?q?=D1=8F=D0=B6=D0=B5=D0=B2?= Date: Wed, 13 Dec 2023 09:43:55 +0300 Subject: [PATCH] react: fix types --- packages/imask/src/controls/input.ts | 2 +- packages/imask/src/masked/factory.ts | 17 ++++++-- packages/react-imask/src/hook.ts | 5 ++- packages/react-imask/src/index.ts | 2 +- packages/react-imask/src/mixin.ts | 64 +++++++++++++++------------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/packages/imask/src/controls/input.ts b/packages/imask/src/controls/input.ts index 347c0eb3..3d1a22fc 100644 --- a/packages/imask/src/controls/input.ts +++ b/packages/imask/src/controls/input.ts @@ -16,7 +16,7 @@ type InputMaskEventListener = (e?: InputEvent) => void; /** Listens to element events and controls changes between element and {@link Masked} */ export default -class InputMask { +class InputMask> { /** View element */ diff --git a/packages/imask/src/masked/factory.ts b/packages/imask/src/masked/factory.ts index 24617b3e..d157b6f7 100644 --- a/packages/imask/src/masked/factory.ts +++ b/packages/imask/src/masked/factory.ts @@ -69,7 +69,17 @@ type FactoryStaticMaskReturnMasked = export -type FactoryInstanceOpts = MaskedOptions & { mask: Masked }; +type FactoryInstanceOpts = + | { mask: MaskedDate } & Omit + | { mask: MaskedNumber } & Omit + | { mask: MaskedEnum } & Omit + | { mask: MaskedRange } & Omit + | { mask: MaskedRegExp } & Omit + | { mask: MaskedFunction } & Omit + | { mask: MaskedPattern } & Omit + | { mask: MaskedDynamic } & Omit + | { mask: Masked } & Omit +; export type FactoryInstanceReturnMasked = Opts extends { mask: infer M } ? M : never; @@ -133,8 +143,8 @@ type UpdateInstanceOpts = M extends MaskedDate ? MaskedDateOptions : M extends MaskedNumber ? MaskedNumberOptions : M extends MaskedDynamic ? MaskedDynamicOptions : - M extends MaskedRange ? MaskedRangeOptions : - M extends MaskedEnum ? MaskedEnumOptions : + M extends MaskedRange ? MaskedRangeOptions & { mask: MaskedRange } : + M extends MaskedEnum ? MaskedEnumOptions & { mask: MaskedEnum } : M extends MaskedPattern ? MaskedPatternOptions : AnyOpts ; @@ -184,7 +194,6 @@ type FactoryReturnMasked = ; - // TODO can't use overloads here because of https://github.com/microsoft/TypeScript/issues/50754 // export function maskedClass(mask: string): typeof MaskedPattern; // export function maskedClass(mask: DateConstructor): typeof MaskedDate; diff --git a/packages/react-imask/src/hook.ts b/packages/react-imask/src/hook.ts index f29b6c0b..beed8014 100644 --- a/packages/react-imask/src/hook.ts +++ b/packages/react-imask/src/hook.ts @@ -10,7 +10,10 @@ function useIMask< Opts extends FactoryOpts=FactoryOpts, >( opts: Opts, - { onAccept, onComplete }: Partial, 'onAccept' | 'onComplete'>> = {} + { onAccept, onComplete }: { + onAccept?: (value: InputMask['value'], maskRef: InputMask, e?: InputEvent) => void; + onComplete?: (value: InputMask['value'], maskRef: InputMask, e?: InputEvent) => void; + } = {} ): { ref: MutableRefObject, maskRef: MutableRefObject | null>, diff --git a/packages/react-imask/src/index.ts b/packages/react-imask/src/index.ts index f7c26ca4..b47a2d9d 100644 --- a/packages/react-imask/src/index.ts +++ b/packages/react-imask/src/index.ts @@ -4,7 +4,7 @@ export { default as IMaskInput } from './input'; export { default as useIMask } from './hook'; export { default as IMaskMixin, type MaskPropsKeys, - type MaskOpts, + type ExtractMaskOpts, type ReactElementProps, type ReactMaskProps, type ReactMixinComponent, diff --git a/packages/react-imask/src/mixin.ts b/packages/react-imask/src/mixin.ts index d903f33c..b111ce8a 100644 --- a/packages/react-imask/src/mixin.ts +++ b/packages/react-imask/src/mixin.ts @@ -3,11 +3,13 @@ import PropTypes from 'prop-types'; import IMask, { type InputMask, type InputMaskElement, type FactoryOpts, type AllFactoryStaticOpts } from 'imask'; +type AnyProps = Record; + export type Falsy = false | 0 | "" | null | undefined; export -type ReactMaskOpts = Opts & { unmask?: 'typed' | boolean }; +type ReactMaskOpts = FactoryOpts & { unmask?: 'typed' | boolean }; export type UnmaskValue = @@ -16,17 +18,23 @@ type UnmaskValue = InputMask['unmaskedValue'] ; +export +type ExtractReactMaskOpts< + MaskElement extends InputMaskElement, + Props extends IMaskInputProps, +> = Extract; + export type ReactMaskProps< MaskElement extends InputMaskElement, - Opts extends ReactMaskOpts=ReactMaskOpts, + Props extends IMaskInputProps=AnyProps, > = { - onAccept?: (value: UnmaskValue, maskRef: InputMask, e?: InputEvent) => void; - onComplete?: (value: UnmaskValue, maskRef: InputMask, e?: InputEvent) => void; - unmask?: Opts['unmask']; - value?: UnmaskValue; + onAccept?: (value: UnmaskValue>, maskRef: InputMask>, e?: InputEvent) => void; + onComplete?: (value: UnmaskValue>, maskRef: InputMask>, e?: InputEvent) => void; + unmask?: ExtractReactMaskOpts['unmask']; + value?: UnmaskValue>; inputRef?: React.Ref; - ref?: React.Ref>>; + ref?: React.Ref>; } const MASK_PROPS: { [key in keyof (AllFactoryStaticOpts & ReactMaskProps)]: any } = { @@ -116,16 +124,18 @@ const MASK_PROPS_NAMES = (Object.keys(MASK_PROPS) as Array = Omit, keyof typeof MASK_PROPS>, typeof NON_MASK_OPTIONS_PROPS_NAMES[number]>; +type ReactElementProps = + Omit, keyof typeof MASK_PROPS>, typeof NON_MASK_OPTIONS_PROPS_NAMES[number]>; + type NonMaskProps< MaskElement extends InputMaskElement, - Props extends IMaskMixinProps=IMaskMixinProps + Props extends IMaskMixinProps=AnyProps > = Omit; export type ReactMixinComponent< MaskElement extends InputMaskElement, - Props extends IMaskInputProps, + Props extends IMaskMixinProps=AnyProps, > = React.ComponentType< & ReactElementProps & { inputRef: React.Ref } @@ -139,25 +149,19 @@ const MASK_OPTIONS_PROPS_NAMES = MASK_PROPS_NAMES.filter(pName => ) as Array; export -type MaskOpts< +type ExtractMaskOpts< MaskElement extends InputMaskElement, - Props extends IMaskInputProps=IMaskInputProps + Props extends IMaskInputProps, > = Extract; export -type IMaskMixinProps< - MaskElement extends InputMaskElement, - Props extends (ReactMaskOpts & ReactMaskProps)=ReactMaskOpts & ReactMaskProps, -> = Omit, 'ref'> & MaskOpts; +type IMaskMixinProps = + Omit, 'ref'> & FactoryOpts; export -type IMaskInputProps< - MaskElement extends InputMaskElement, - Props extends IMaskMixinProps=IMaskMixinProps, -> = ReactElementProps & IMaskMixinProps; - +type IMaskInputProps< MaskElement extends InputMaskElement> = + ReactElementProps & IMaskMixinProps; -type AnyProps = Record; export default function IMaskMixin< @@ -169,7 +173,7 @@ function IMaskMixin< static propTypes: typeof MASK_PROPS; declare element: MaskElement; - declare maskRef?: InputMask>; + declare maskRef?: InputMask>; constructor (props: Props) { super(props); @@ -215,7 +219,7 @@ function IMaskMixin< } } - initMask (maskOptions: MaskOpts = this._extractMaskOptionsFromProps(this.props)) { + initMask (maskOptions: ExtractMaskOpts = this._extractMaskOptionsFromProps(this.props)) { this.maskRef = IMask(this.element, maskOptions) .on('accept', this._onAccept.bind(this)) .on('complete', this._onComplete.bind(this)); @@ -230,7 +234,7 @@ function IMaskMixin< } } - _extractMaskOptionsFromProps (props: Readonly): MaskOpts { + _extractMaskOptionsFromProps (props: Readonly): ExtractMaskOpts { const { ...cloneProps }: Readonly = props; // keep only mask options @@ -240,7 +244,7 @@ function IMaskMixin< delete cloneProps[nonMaskProp]; }); - return cloneProps as MaskOpts; + return cloneProps as ExtractMaskOpts; } _extractNonMaskProps (props: Readonly): NonMaskProps { @@ -255,18 +259,18 @@ function IMaskMixin< return cloneProps as NonMaskProps; } - get maskValue (): UnmaskValue { - if (!this.maskRef) return '' as UnmaskValue; + get maskValue (): UnmaskValue> { + if (!this.maskRef) return '' as UnmaskValue>; if (this.props.unmask === 'typed') return this.maskRef.typedValue; if (this.props.unmask) return this.maskRef.unmaskedValue; return this.maskRef.value; } - set maskValue (value: UnmaskValue) { + set maskValue (value: UnmaskValue>) { if (!this.maskRef) return; - value = (value == null && this.props.unmask !== 'typed' ? '' : value) as UnmaskValue; + value = (value == null && this.props.unmask !== 'typed' ? '' : value) as UnmaskValue>; if (this.props.unmask === 'typed') this.maskRef.typedValue = value; else if (this.props.unmask) this.maskRef.unmaskedValue = value; else this.maskRef.value = value;