Skip to content

Commit 2d005af

Browse files
committed
Update TS
1 parent 6d9e3d5 commit 2d005af

File tree

2 files changed

+105
-9
lines changed

2 files changed

+105
-9
lines changed

src/CodeField.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import {
2+
Omit,
23
StyleProp,
34
TextInput,
45
TextInputProps,
56
TextStyle,
67
View,
78
ViewProps,
89
} from 'react-native';
9-
import React, {ComponentType, ReactNode, Ref} from 'react';
10+
import React, {
11+
ComponentPropsWithRef,
12+
ComponentType,
13+
ElementType,
14+
forwardRef,
15+
ReactElement,
16+
ReactNode,
17+
Ref,
18+
RefAttributes,
19+
} from 'react';
1020
import {getStyle, getSymbols} from './utils';
1121
import {useFocusState} from './useFocusState';
1222

@@ -18,13 +28,12 @@ export interface RenderCellOptions {
1828
isFocused: boolean;
1929
}
2030

21-
type TextInputPropsWithoutStyle = Omit<TextInputProps, 'style'>;
31+
type OmitStyle<T extends {style?: any}> = Omit<T, 'style'>;
2232

23-
export interface Props extends TextInputPropsWithoutStyle {
33+
interface BaseProps {
2434
renderCell: (options: RenderCellOptions) => ReactNode;
2535
RootProps?: ViewProps;
2636
RootComponent?: ComponentType<ViewProps>;
27-
InputComponent?: ComponentType<TextInputProps>;
2837
rootStyle?: ViewProps['style'];
2938
textInputStyle?: StyleProp<TextStyle>;
3039
cellCount?: number;
@@ -45,7 +54,7 @@ function CodeFieldComponent(
4554
RootComponent = View,
4655
InputComponent = TextInput,
4756
...rest
48-
}: Props,
57+
}: Props & {InputComponent?: ComponentType<any>},
4958
ref: Ref<TextInput>,
5059
) {
5160
const focusState = useFocusState(onBlur, onFocus);
@@ -87,4 +96,22 @@ function CodeFieldComponent(
8796
);
8897
}
8998

90-
export const CodeField = React.forwardRef(CodeFieldComponent);
99+
export interface Props
100+
extends BaseProps,
101+
OmitStyle<TextInputProps>,
102+
RefAttributes<TextInput> {
103+
//
104+
}
105+
106+
export interface CodeFieldOverridableComponent {
107+
<C extends ElementType>(
108+
props: {InputComponent: C} & OmitStyle<ComponentPropsWithRef<C>> &
109+
BaseProps,
110+
): ReactElement;
111+
112+
(props: Props): ReactElement;
113+
}
114+
115+
export const CodeField = forwardRef(
116+
CodeFieldComponent,
117+
) as CodeFieldOverridableComponent;

src/__tests__/CodeField.test.tsx

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React, {ComponentProps} from 'react';
2-
import {View, Text} from 'react-native';
3-
import {render, act} from '@testing-library/react-native';
1+
import React, {ComponentProps, ForwardedRef, forwardRef} from 'react';
2+
import {Text, TextInput, TextInputProps, View} from 'react-native';
3+
import {act, render} from '@testing-library/react-native';
44
import {CodeField} from '../CodeField';
55
import {styles} from '../CodeField.styles';
66

@@ -82,3 +82,72 @@ it('should invoke renderCell for third cell when isFocused and it empty', () =>
8282
[{index: 3, isFocused: false, symbol: ''}],
8383
]);
8484
});
85+
86+
{
87+
console.log(
88+
<CodeField
89+
renderCell={() => null}
90+
ref={(ref: TextInput | null) => {
91+
ref?.focus();
92+
ref?.blur();
93+
}}
94+
/>,
95+
);
96+
97+
console.log(
98+
// @ts-expect-error - number is not function
99+
<CodeField
100+
onChangeText={123}
101+
renderCell={() => null}
102+
ref={(ref: TextInput | null) => {
103+
ref?.focus();
104+
ref?.blur();
105+
}}
106+
/>,
107+
);
108+
}
109+
110+
{
111+
interface MyTextInput extends TextInputProps {
112+
myRequiredProps: string;
113+
}
114+
115+
// eslint-disable-next-line react/display-name
116+
const MyTextInput = forwardRef(
117+
(props: MyTextInput, ref: ForwardedRef<TextInput>) => (
118+
<View testID={props.myRequiredProps}>
119+
<TextInput ref={ref} />
120+
</View>
121+
),
122+
);
123+
124+
console.log(
125+
<CodeField
126+
renderCell={() => null}
127+
myRequiredProps="my-required-props"
128+
InputComponent={MyTextInput}
129+
/>,
130+
);
131+
132+
console.log(
133+
// @ts-expect-error - `myRequiredProps` is required prop
134+
<CodeField<typeof MyTextInput>
135+
renderCell={() => null}
136+
InputComponent={MyTextInput}
137+
/>,
138+
);
139+
140+
console.log(
141+
// @ts-expect-error - `myRequiredProps` is required prop
142+
<CodeField renderCell={() => null} InputComponent={MyTextInput} />,
143+
);
144+
145+
console.log(
146+
<CodeField
147+
renderCell={() => null}
148+
// @ts-expect-error - number is not string
149+
myRequiredProps={1}
150+
InputComponent={MyTextInput}
151+
/>,
152+
);
153+
}

0 commit comments

Comments
 (0)