Skip to content

Commit 3e35a86

Browse files
nitzanyizethanshar
andauthored
Ref Typings (#2885)
* Changed forwardRef typings * Removed test component * Added typings to forwardRef to support ref typing interface * Added typings to forwardRef and asBaseComponents * Changed static to object by default. "Fixed" static properties typings * Changed injected ref typing * Fixed button typing errors * Moved ButtonStatis to types file * Added component statics extraction type * Added usage of components statics extraction type * Added component statics usage to scroll bar * Fixed Slider interface typings and screen * Fixed TextField ref typings * Added fadedScrollView ref interface * Fixed icon statics typings * Fixed gradient slider statics * Fixed FadedScrollView ref typing in tabController * Last TS fixes * Fixed lint errors * Removed empty ref interfaces * TS fix * Fixed imports and formatting --------- Co-authored-by: Ethan Sharabi <[email protected]>
1 parent 93f9a7a commit 3e35a86

File tree

19 files changed

+47
-55
lines changed

19 files changed

+47
-55
lines changed

demo/src/screens/componentScreens/SliderScreen.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ export default class SliderScreen extends Component<SliderScreenProps, SliderScr
264264
color={color}
265265
containerStyle={styles.gradientSliderContainer}
266266
onValueChange={this.onGradientValueChange}
267-
// @ts-expect-error
268267
ref={this.gradientSlider}
269268
/>
270269
<View style={styles.box}>

demo/src/screens/componentScreens/TextFieldScreen.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ export default class TextFieldScreen extends Component {
5959
<Text h3 marginV-s4>
6060
Default
6161
</Text>
62-
{/* @ts-expect-error */}
6362
<TextField ref={this.input} label="Name" placeholder="Enter full name"/>
64-
6563
<Text h3 marginV-s4>
6664
Static vs Floating Placeholder
6765
</Text>
@@ -89,7 +87,6 @@ export default class TextFieldScreen extends Component {
8987
</Text>
9088

9189
<TextField
92-
// @ts-expect-error
9390
ref={this.input2}
9491
placeholder="Enter search term"
9592
text70
@@ -99,7 +96,6 @@ export default class TextFieldScreen extends Component {
9996
/>
10097

10198
<TextField
102-
// @ts-expect-error
10399
ref={this.input2}
104100
placeholder="Enter URL"
105101
floatingPlaceholder
@@ -114,7 +110,6 @@ export default class TextFieldScreen extends Component {
114110
/>
115111

116112
<TextField
117-
// @ts-expect-error
118113
ref={this.input2}
119114
placeholder="Enter weight"
120115
text70
@@ -166,7 +161,6 @@ export default class TextFieldScreen extends Component {
166161

167162
<View row top marginT-s4>
168163
<TextField
169-
// @ts-expect-error
170164
ref={this.inputWithValidation}
171165
placeholder="Enter full name"
172166
validate="required"

demo/src/screens/componentScreens/TextScreen.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class TextScreen extends Component {
124124
<Text
125125
text70
126126
animated
127-
// @ts-expect-error
128127
style={{transform: [{scale: this.animatedValue.interpolate({inputRange: [0, 1], outputRange: [1, 2]})}]}}
129128
onPress={this.animate}
130129
>

demo/src/screens/incubatorScreens/IncubatorSliderScreen.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ const IncubatorSliderScreen = () => {
2323
const [color, setColor] = useState(COLOR);
2424
const [alpha, setAlpha] = useState(1);
2525

26-
const slider = useRef<typeof Incubator.Slider>();
27-
const customSlider = useRef<typeof Incubator.Slider>();
28-
const negativeSlider = useRef<typeof Incubator.Slider>();
29-
const rangeSlider = useRef<typeof Incubator.Slider>();
26+
const slider = useRef<Incubator.SliderRef>(null);
27+
const customSlider = useRef<Incubator.SliderRef>(null);
28+
const negativeSlider = useRef<Incubator.SliderRef>(null);
29+
const rangeSlider = useRef<Incubator.SliderRef>(null);
3030

3131
const resetSliders = useCallback(() => {
3232
slider.current?.reset();
@@ -92,7 +92,6 @@ const IncubatorSliderScreen = () => {
9292
</Text>
9393
{renderValuesBox(sliderValue)}
9494
<Incubator.Slider
95-
// @ts-expect-error TODO: need to properly support SliderMethods type to use for ref
9695
ref={slider}
9796
onValueChange={onValueChange}
9897
containerStyle={styles.container}
@@ -124,7 +123,6 @@ const IncubatorSliderScreen = () => {
124123
</Text>
125124
{renderValuesBox(customSliderValue)}
126125
<Incubator.Slider
127-
// @ts-expect-error
128126
ref={customSlider}
129127
onValueChange={onCustomValueChange}
130128
value={20}
@@ -152,7 +150,6 @@ const IncubatorSliderScreen = () => {
152150
</Text>
153151
{renderValuesBox(negativeSliderValue)}
154152
<Incubator.Slider
155-
// @ts-expect-error
156153
ref={negativeSlider}
157154
onValueChange={onNegativeValueChange}
158155
value={-30}
@@ -175,7 +172,6 @@ const IncubatorSliderScreen = () => {
175172
<View marginH-20>
176173
{renderValuesBox(sliderMinValue, sliderMaxValue)}
177174
<Incubator.Slider
178-
// @ts-expect-error
179175
ref={rangeSlider}
180176
useRange
181177
onRangeChange={onRangeChange}

src/commons/asBaseComponent.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import hoistStatics from 'hoist-non-react-statics';
33
import * as Modifiers from './modifiers';
44
import {Scheme, SchemeChangeListener, ThemeManager} from '../style';
5-
import forwardRef from './forwardRef';
5+
import forwardRef, {ForwardRefInjectedProps} from './forwardRef';
66
import UIComponent from './UIComponent';
77

88
export interface BaseComponentInjectedProps {
@@ -21,9 +21,9 @@ export interface AsBaseComponentOptions {
2121
const EMPTY_MODIFIERS = {};
2222
const colorScheme = Scheme.getSchemeType();
2323

24-
function asBaseComponent<PROPS, STATICS = {}>(WrappedComponent: React.ComponentType<any>,
25-
options: AsBaseComponentOptions = {}): React.ComponentClass<PROPS> & STATICS {
26-
class BaseComponent extends UIComponent {
24+
function asBaseComponent<PROPS, STATICS = {}, RefInterface = any>(WrappedComponent: React.ComponentType<any>,
25+
options: AsBaseComponentOptions = {}) {
26+
class BaseComponent extends UIComponent<PROPS & ForwardRefInjectedProps<RefInterface>> {
2727
static displayName: string | undefined;
2828
static propTypes: any;
2929
static defaultProps: any;
@@ -85,8 +85,7 @@ function asBaseComponent<PROPS, STATICS = {}>(WrappedComponent: React.ComponentT
8585
if (ThemeContext) {
8686
BaseComponent.contextType = ThemeContext;
8787
}
88-
89-
return forwardRef(BaseComponent) as any;
88+
return forwardRef<PROPS, STATICS, RefInterface>(BaseComponent);
9089
}
9190

9291
export default asBaseComponent;

src/commons/forwardRef.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
1-
import React from 'react';
1+
import React, {ComponentType, ForwardedRef} from 'react';
22
import hoistStatics from 'hoist-non-react-statics';
33

4-
export interface ForwardRefInjectedProps {
4+
export interface ForwardRefInjectedProps<T = any> {
55
/**
66
* The forwarded ref of the containing element
77
*/
8-
forwardedRef: any;
8+
forwardedRef: ForwardedRef<T>;
99
}
1010

11-
export default function forwardRef<P = any, STATICS = {}>(WrappedComponent: React.ComponentType<P>): React.ComponentType<P> & STATICS {
12-
function forwardRef(props: P, ref: any) {
11+
export default function forwardRef<P, STATICS = {}, RefInterface = any>(WrappedComponent: ComponentType<P & ForwardRefInjectedProps<RefInterface>>) {
12+
function forwardRef(props: P, ref: ForwardedRef<RefInterface>) {
1313
return <WrappedComponent {...props} forwardedRef={ref}/>;
1414
}
1515

16-
const ForwardedComponent = React.forwardRef(forwardRef);
16+
const ForwardedComponent = React.forwardRef<RefInterface, P>(forwardRef);
1717

1818
hoistStatics(ForwardedComponent, WrappedComponent);
19+
//@ts-ignore
1920
ForwardedComponent.displayName = WrappedComponent.displayName;
2021
//@ts-ignore
2122
ForwardedComponent.propTypes = WrappedComponent.propTypes;
2223
//@ts-ignore
2324
ForwardedComponent.defaultProps = WrappedComponent.defaultProps;
2425

25-
return ForwardedComponent as any;
26+
return ForwardedComponent as typeof ForwardedComponent & STATICS;
2627
}

src/components/button/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {Platform, StyleSheet, LayoutAnimation, LayoutChangeEvent, ImageStyle, Te
44
import {asBaseComponent, forwardRef, Constants} from '../../commons/new';
55
import {Colors, Typography, BorderRadiuses} from 'style';
66
import TouchableOpacity from '../touchableOpacity';
7-
import type {Dictionary} from '../../typings/common';
7+
import type {Dictionary, ComponentStatics} from '../../typings/common';
88
import Text from '../text';
99
import Image from '../image';
1010
import Icon from '../icon';
@@ -21,7 +21,6 @@ import {PADDINGS, HORIZONTAL_PADDINGS, MIN_WIDTH, DEFAULT_SIZE} from './ButtonCo
2121

2222
export {ButtonSize, ButtonAnimationDirection, ButtonProps};
2323

24-
2524
class Button extends PureComponent<Props, ButtonState> {
2625
static displayName = 'Button';
2726

@@ -429,5 +428,6 @@ const modifiersOptions = {
429428
typography: true,
430429
color: true
431430
};
432-
433-
export default asBaseComponent<ButtonProps, typeof Button>(forwardRef<Props>(Button), {modifiersOptions});
431+
export default asBaseComponent<ButtonProps, ComponentStatics<typeof Button>, {}>(forwardRef(Button), {
432+
modifiersOptions
433+
});

src/components/fadedScrollView/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import {
66
NativeScrollEvent,
77
LayoutChangeEvent
88
} from 'react-native';
9+
import {ScrollView as GestureScrollView} from 'react-native-gesture-handler';
910
import Fader, {FaderProps} from '../fader';
1011
import useScrollEnabler from '../../hooks/useScrollEnabler';
1112
import useScrollReached from '../../hooks/useScrollReached';
1213
import {forwardRef, ForwardRefInjectedProps} from '../../commons/new';
13-
import {ScrollView as GestureScrollView} from 'react-native-gesture-handler';
14+
import {ComponentStatics} from '../../typings/common';
1415

1516
export type FadedScrollViewProps = ScrollViewProps & {
1617
/**
@@ -37,7 +38,7 @@ export type FadedScrollViewProps = ScrollViewProps & {
3738
};
3839

3940
type Props = FadedScrollViewProps & ForwardRefInjectedProps;
40-
interface Statics {
41+
export interface FadedScrollViewRef {
4142
scrollTo(
4243
y?: number | {x?: number | undefined; y?: number | undefined; animated?: boolean | undefined},
4344
x?: number,
@@ -139,5 +140,4 @@ const FadedScrollView = (props: Props) => {
139140
};
140141

141142
FadedScrollView.displayName = 'IGNORE';
142-
// @ts-expect-error
143-
export default forwardRef<FadedScrollViewProps, Statics>(FadedScrollView);
143+
export default forwardRef<FadedScrollViewProps, ComponentStatics<FadedScrollViewProps>, FadedScrollViewRef>(FadedScrollView);

src/components/icon/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import isUndefined from 'lodash/isUndefined';
22
import React, {useMemo, forwardRef} from 'react';
33
import {Image, ImageProps, StyleSheet} from 'react-native';
44
import {asBaseComponent, BaseComponentInjectedProps, MarginModifiers, Constants} from '../../commons/new';
5+
import {ComponentStatics} from '../../typings/common';
56
import {getAsset, isSvg, isBase64ImageContent} from '../../utils/imageUtils';
67
import {RecorderProps} from '../../typings/recorderTypes';
78
import SvgImage from '../svgImage';
@@ -89,7 +90,8 @@ Icon.displayName = 'Icon';
8990
Icon.defaultProps = {
9091
assetGroup: 'icons'
9192
};
92-
export default asBaseComponent<IconProps, typeof Icon>(Icon, {modifiersOptions: {margins: true}});
93+
94+
export default asBaseComponent<IconProps, ComponentStatics<typeof Icon>>(Icon, {modifiersOptions: {margins: true}});
9395

9496
const styles = StyleSheet.create({
9597
rtlFlipped: {

src/components/pageControl/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import _ from 'lodash';
22
import React, {PureComponent} from 'react';
33
import {StyleSheet, LayoutAnimation, StyleProp, ViewStyle} from 'react-native';
4-
import {asBaseComponent, forwardRef} from '../../commons/new';
4+
import {asBaseComponent} from '../../commons/new';
55
import {Colors} from '../../style';
66
import TouchableOpacity, {TouchableOpacityProps} from '../touchableOpacity';
77
import View from '../view';
@@ -239,7 +239,8 @@ class PageControl extends PureComponent<PageControlProps, State> {
239239
}
240240
}
241241

242-
export default asBaseComponent<PageControlProps>(forwardRef(PageControl));
242+
// @ts-expect-error
243+
export default asBaseComponent<PageControlProps>(PageControl);
243244

244245
const styles = StyleSheet.create({
245246
container: {

src/components/scrollBar/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import {ScrollView, FlatList} from 'react-native-gesture-handler';
1212
import {Colors} from '../../style';
1313
import {Constants, asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
14+
import {ComponentStatics} from '../../typings/common';
1415
import View from '../view';
1516
import Image from '../image';
1617

@@ -276,4 +277,4 @@ const Item = ({children, index, onLayout}: any) => {
276277

277278
Item.displayName = 'IGNORE';
278279
ScrollBar.Item = Item;
279-
export default asBaseComponent<ScrollBarProps, typeof ScrollBar>(forwardRef(ScrollBar));
280+
export default asBaseComponent<ScrollBarProps, ComponentStatics<typeof ScrollBar>>(forwardRef(ScrollBar));

src/components/slider/GradientSlider.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, {useCallback, useEffect, useState} from 'react';
44
import {StyleProp, ViewStyle} from 'react-native';
55
import {Colors} from '../../style';
66
import {asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
7+
import {ComponentStatics} from '../../typings/common';
78
import Slider, {SliderProps} from './index';
89
import {Slider as NewSlider} from '../../incubator';
910
import {SliderContextProps} from './context/SliderContext';
@@ -192,7 +193,6 @@ const GradientSlider = (props: Props) => {
192193
return (
193194
<SliderComponent
194195
{...others}
195-
//@ts-expect-error
196196
ref={forwardedRef}
197197
onReset={reset}
198198
renderTrack={renderTrack}
@@ -213,4 +213,5 @@ GradientSlider.displayName = 'GradientSlider';
213213
GradientSlider.types = GradientSliderTypes;
214214

215215
// eslint-disable-next-line max-len
216-
export default asBaseComponent<GradientSliderProps, typeof GradientSlider>(forwardRef(asSliderGroupChild(forwardRef(GradientSlider))));
216+
// @ts-expect-error
217+
export default asBaseComponent<GradientSliderProps, ComponentStatics<typeof GradientSlider>>(forwardRef(asSliderGroupChild(forwardRef(GradientSlider))));

src/components/tabController/TabBar.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '../../commons/new';
1414
import View from '../view';
1515
import {Colors, Spacings, Typography} from '../../style';
16-
import FadedScrollView from '../fadedScrollView';
16+
import FadedScrollView, {FadedScrollViewRef} from '../fadedScrollView';
1717
import {FaderProps} from '../fader';
1818
import useScrollToItem from './useScrollToItem';
1919
import {useDidUpdate} from 'hooks';
@@ -161,7 +161,7 @@ const TabBar = (props: Props) => {
161161
testID
162162
} = props;
163163

164-
const tabBar = useRef<typeof FadedScrollView>();
164+
const tabBar = useRef<FadedScrollViewRef>(null);
165165
const [key, setKey] = useState<string>(generateKey(Constants.orientation, labelColor, selectedLabelColor));
166166
const context = useContext(TabBarContext);
167167
const {items: contextItems, currentPage, targetPage, containerWidth: contextContainerWidth} = context;
@@ -295,7 +295,6 @@ const TabBar = (props: Props) => {
295295
return (
296296
<View style={_containerStyle} key={key} bg-$backgroundElevated>
297297
<FadedScrollView
298-
// @ts-expect-error
299298
ref={tabBar}
300299
horizontal
301300
showsHorizontalScrollIndicator={false}

src/components/text/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export interface HighlightStringProps {
4747

4848
export type HighlightString = string | HighlightStringProps;
4949

50-
export type TextProps = RNTextProps &
50+
export type TextProps = Omit<RNTextProps, 'style'> &
5151
TypographyModifiers &
5252
ColorsModifiers &
5353
MarginModifiers &

src/components/textField/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export {
235235
ValidationMessagePositionType as TextFieldValidationMessagePositionType,
236236
MandatoryIndication as TextFieldMandatoryIndication
237237
};
238-
export default asBaseComponent<TextFieldProps, StaticMembers>(forwardRef(TextField as any), {
238+
export default asBaseComponent<TextFieldProps, StaticMembers, TextFieldRef>(forwardRef(TextField as any), {
239239
modifiersOptions: {
240240
margins: true,
241241
paddings: true,

src/incubator/Slider/index.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from './SliderPresenter';
1616
import Thumb from './Thumb';
1717
import Track from './Track';
18-
18+
import {ComponentStatics} from '../../typings/common';
1919
export interface SliderProps extends AccessibilityProps {
2020
/**
2121
* Initial value
@@ -131,8 +131,8 @@ export interface SliderProps extends AccessibilityProps {
131131
migrate?: boolean;
132132
}
133133

134-
type Props = SliderProps & ForwardRefInjectedProps;
135-
interface Statics {
134+
type Props = SliderProps & ForwardRefInjectedProps<SliderRef>;
135+
export interface SliderRef {
136136
reset: () => void;
137137
}
138138

@@ -398,8 +398,7 @@ const Slider = React.memo((props: Props) => {
398398
);
399399
});
400400

401-
// @ts-expect-error
402-
export default forwardRef<SliderProps, Statics>(Slider);
401+
export default forwardRef<SliderProps, ComponentStatics<typeof Slider>, SliderRef>(Slider);
403402

404403
const styles = StyleSheet.create({
405404
container: {

src/incubator/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export {
1313
export {default as Toast, ToastProps, ToastPresets} from './toast';
1414
export {default as TouchableOpacity, TouchableOpacityProps} from './TouchableOpacity';
1515
export {default as PanView, PanViewProps, PanViewDirections, PanViewDismissThreshold} from './panView';
16-
export {default as Slider} from './Slider';
16+
export {default as Slider, SliderRef} from './Slider';
1717
export {default as Dialog, DialogProps, DialogHeaderProps, DialogStatics, DialogImperativeMethods} from './Dialog';
1818
// TODO: delete exports after fully removing from private
1919
export {default as ChipsInput, ChipsInputProps, ChipsInputChangeReason, ChipsInputChipProps} from '../components/chipsInput';

src/incubator/toast/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ const Toast = (props: PropsWithChildren<ToastProps>) => {
164164
<View accessible={Constants.isIOS} style={styles.messageContainer}>
165165
<Text
166166
testID={`${testID}-message`}
167-
// @ts-expect-error
168167
ref={viewRef}
169168
style={[styles.message, {textAlign}, messageStyle]}
170169
accessibilityLabel={toastPreset.accessibilityMessage}

src/typings/common.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ export type ExtendTypeWith<T extends Constructor<any>, OtherObject extends objec
88
ConstructorParameters<T>
99
>;
1010
export type Dictionary<TYPE> = {[key: string]: TYPE};
11+
12+
export type ComponentStatics<T> = {[Key in keyof T]: T[Key]}

0 commit comments

Comments
 (0)