Skip to content

Ref Typings #2885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b1149bd
Changed forwardRef typings
nitzanyiz Jan 9, 2024
fd3a4df
Removed test component
nitzanyiz Jan 9, 2024
b53f3a3
Added typings to forwardRef to support ref typing interface
nitzanyiz Jan 9, 2024
76738f6
Added typings to forwardRef and asBaseComponents
nitzanyiz Jan 10, 2024
9e678a8
Changed static to object by default. "Fixed" static properties typings
nitzanyiz Jan 10, 2024
a0d9dee
Changed injected ref typing
nitzanyiz Jan 10, 2024
4d06fd7
Fixed button typing errors
nitzanyiz Jan 10, 2024
700b5e2
Moved ButtonStatis to types file
nitzanyiz Jan 10, 2024
d15753c
Added component statics extraction type
nitzanyiz Jan 11, 2024
34afc9d
Added usage of components statics extraction type
nitzanyiz Jan 11, 2024
2641169
Added component statics usage to scroll bar
nitzanyiz Jan 11, 2024
40eb1e5
Merge remote-tracking branch 'origin' into infra/RefTypings
nitzanyiz Jan 11, 2024
2d3ba2e
Fixed Slider interface typings and screen
nitzanyiz Jan 11, 2024
fee312b
Fixed TextField ref typings
nitzanyiz Jan 11, 2024
fed6f62
Added fadedScrollView ref interface
nitzanyiz Jan 11, 2024
0dafa42
Fixed icon statics typings
nitzanyiz Jan 11, 2024
fdf7c34
Fixed gradient slider statics
nitzanyiz Jan 11, 2024
f0e702a
Fixed FadedScrollView ref typing in tabController
nitzanyiz Jan 11, 2024
200fd5f
Last TS fixes
ethanshar Jan 11, 2024
f7ea4c7
Fixed lint errors
nitzanyiz Jan 11, 2024
7e65b5e
Removed empty ref interfaces
nitzanyiz Jan 11, 2024
cb24523
TS fix
nitzanyiz Jan 11, 2024
83af2e0
Fixed imports and formatting
nitzanyiz Jan 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion demo/src/screens/componentScreens/SliderScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ export default class SliderScreen extends Component<SliderScreenProps, SliderScr
color={color}
containerStyle={styles.gradientSliderContainer}
onValueChange={this.onGradientValueChange}
// @ts-expect-error
ref={this.gradientSlider}
/>
<View style={styles.box}>
Expand Down
6 changes: 0 additions & 6 deletions demo/src/screens/componentScreens/TextFieldScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ export default class TextFieldScreen extends Component {
<Text h3 marginV-s4>
Default
</Text>
{/* @ts-expect-error */}
<TextField ref={this.input} label="Name" placeholder="Enter full name"/>

<Text h3 marginV-s4>
Static vs Floating Placeholder
</Text>
Expand Down Expand Up @@ -89,7 +87,6 @@ export default class TextFieldScreen extends Component {
</Text>

<TextField
// @ts-expect-error
ref={this.input2}
placeholder="Enter search term"
text70
Expand All @@ -99,7 +96,6 @@ export default class TextFieldScreen extends Component {
/>

<TextField
// @ts-expect-error
ref={this.input2}
placeholder="Enter URL"
floatingPlaceholder
Expand All @@ -114,7 +110,6 @@ export default class TextFieldScreen extends Component {
/>

<TextField
// @ts-expect-error
ref={this.input2}
placeholder="Enter weight"
text70
Expand Down Expand Up @@ -166,7 +161,6 @@ export default class TextFieldScreen extends Component {

<View row top marginT-s4>
<TextField
// @ts-expect-error
ref={this.inputWithValidation}
placeholder="Enter full name"
validate="required"
Expand Down
1 change: 0 additions & 1 deletion demo/src/screens/componentScreens/TextScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ class TextScreen extends Component {
<Text
text70
animated
// @ts-expect-error
style={{transform: [{scale: this.animatedValue.interpolate({inputRange: [0, 1], outputRange: [1, 2]})}]}}
onPress={this.animate}
>
Expand Down
12 changes: 4 additions & 8 deletions demo/src/screens/incubatorScreens/IncubatorSliderScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ const IncubatorSliderScreen = () => {
const [color, setColor] = useState(COLOR);
const [alpha, setAlpha] = useState(1);

const slider = useRef<typeof Incubator.Slider>();
const customSlider = useRef<typeof Incubator.Slider>();
const negativeSlider = useRef<typeof Incubator.Slider>();
const rangeSlider = useRef<typeof Incubator.Slider>();
const slider = useRef<Incubator.SliderRef>(null);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to pass null here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using it without null, the type of the ref is Ref<SliderRef | undefined> which causes an error. This error also occurs with regular react native refs. For example using React Native TextInput.
image

const customSlider = useRef<Incubator.SliderRef>(null);
const negativeSlider = useRef<Incubator.SliderRef>(null);
const rangeSlider = useRef<Incubator.SliderRef>(null);

const resetSliders = useCallback(() => {
slider.current?.reset();
Expand Down Expand Up @@ -92,7 +92,6 @@ const IncubatorSliderScreen = () => {
</Text>
{renderValuesBox(sliderValue)}
<Incubator.Slider
// @ts-expect-error TODO: need to properly support SliderMethods type to use for ref
ref={slider}
onValueChange={onValueChange}
containerStyle={styles.container}
Expand Down Expand Up @@ -124,7 +123,6 @@ const IncubatorSliderScreen = () => {
</Text>
{renderValuesBox(customSliderValue)}
<Incubator.Slider
// @ts-expect-error
ref={customSlider}
onValueChange={onCustomValueChange}
value={20}
Expand Down Expand Up @@ -152,7 +150,6 @@ const IncubatorSliderScreen = () => {
</Text>
{renderValuesBox(negativeSliderValue)}
<Incubator.Slider
// @ts-expect-error
ref={negativeSlider}
onValueChange={onNegativeValueChange}
value={-30}
Expand All @@ -175,7 +172,6 @@ const IncubatorSliderScreen = () => {
<View marginH-20>
{renderValuesBox(sliderMinValue, sliderMaxValue)}
<Incubator.Slider
// @ts-expect-error
ref={rangeSlider}
useRange
onRangeChange={onRangeChange}
Expand Down
11 changes: 5 additions & 6 deletions src/commons/asBaseComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import hoistStatics from 'hoist-non-react-statics';
import * as Modifiers from './modifiers';
import {Scheme, SchemeChangeListener, ThemeManager} from '../style';
import forwardRef from './forwardRef';
import forwardRef, {ForwardRefInjectedProps} from './forwardRef';
import UIComponent from './UIComponent';

export interface BaseComponentInjectedProps {
Expand All @@ -21,9 +21,9 @@ export interface AsBaseComponentOptions {
const EMPTY_MODIFIERS = {};
const colorScheme = Scheme.getSchemeType();

function asBaseComponent<PROPS, STATICS = {}>(WrappedComponent: React.ComponentType<any>,
options: AsBaseComponentOptions = {}): React.ComponentClass<PROPS> & STATICS {
class BaseComponent extends UIComponent {
function asBaseComponent<PROPS, STATICS = {}, RefInterface = any>(WrappedComponent: React.ComponentType<any>,
options: AsBaseComponentOptions = {}) {
class BaseComponent extends UIComponent<PROPS & ForwardRefInjectedProps<RefInterface>> {
static displayName: string | undefined;
static propTypes: any;
static defaultProps: any;
Expand Down Expand Up @@ -85,8 +85,7 @@ function asBaseComponent<PROPS, STATICS = {}>(WrappedComponent: React.ComponentT
if (ThemeContext) {
BaseComponent.contextType = ThemeContext;
}

return forwardRef(BaseComponent) as any;
return forwardRef<PROPS, STATICS, RefInterface>(BaseComponent);
}

export default asBaseComponent;
15 changes: 8 additions & 7 deletions src/commons/forwardRef.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import React from 'react';
import React, {ComponentType, ForwardedRef} from 'react';
import hoistStatics from 'hoist-non-react-statics';

export interface ForwardRefInjectedProps {
export interface ForwardRefInjectedProps<T = any> {
/**
* The forwarded ref of the containing element
*/
forwardedRef: any;
forwardedRef: ForwardedRef<T>;
}

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

const ForwardedComponent = React.forwardRef(forwardRef);
const ForwardedComponent = React.forwardRef<RefInterface, P>(forwardRef);

hoistStatics(ForwardedComponent, WrappedComponent);
//@ts-ignore
ForwardedComponent.displayName = WrappedComponent.displayName;
//@ts-ignore
ForwardedComponent.propTypes = WrappedComponent.propTypes;
//@ts-ignore
ForwardedComponent.defaultProps = WrappedComponent.defaultProps;

return ForwardedComponent as any;
return ForwardedComponent as typeof ForwardedComponent & STATICS;
}
8 changes: 4 additions & 4 deletions src/components/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Platform, StyleSheet, LayoutAnimation, LayoutChangeEvent, ImageStyle, Te
import {asBaseComponent, forwardRef, Constants} from '../../commons/new';
import {Colors, Typography, BorderRadiuses} from 'style';
import TouchableOpacity from '../touchableOpacity';
import type {Dictionary} from '../../typings/common';
import type {Dictionary, ComponentStatics} from '../../typings/common';
import Text from '../text';
import Image from '../image';
import Icon from '../icon';
Expand All @@ -21,7 +21,6 @@ import {PADDINGS, HORIZONTAL_PADDINGS, MIN_WIDTH, DEFAULT_SIZE} from './ButtonCo

export {ButtonSize, ButtonAnimationDirection, ButtonProps};


class Button extends PureComponent<Props, ButtonState> {
static displayName = 'Button';

Expand Down Expand Up @@ -429,5 +428,6 @@ const modifiersOptions = {
typography: true,
color: true
};

export default asBaseComponent<ButtonProps, typeof Button>(forwardRef<Props>(Button), {modifiersOptions});
export default asBaseComponent<ButtonProps, ComponentStatics<typeof Button>, {}>(forwardRef(Button), {
modifiersOptions
});
8 changes: 4 additions & 4 deletions src/components/fadedScrollView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
NativeScrollEvent,
LayoutChangeEvent
} from 'react-native';
import {ScrollView as GestureScrollView} from 'react-native-gesture-handler';
import Fader, {FaderProps} from '../fader';
import useScrollEnabler from '../../hooks/useScrollEnabler';
import useScrollReached from '../../hooks/useScrollReached';
import {forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import {ScrollView as GestureScrollView} from 'react-native-gesture-handler';
import {ComponentStatics} from '../../typings/common';

export type FadedScrollViewProps = ScrollViewProps & {
/**
Expand All @@ -37,7 +38,7 @@ export type FadedScrollViewProps = ScrollViewProps & {
};

type Props = FadedScrollViewProps & ForwardRefInjectedProps;
interface Statics {
export interface FadedScrollViewRef {
scrollTo(
y?: number | {x?: number | undefined; y?: number | undefined; animated?: boolean | undefined},
x?: number,
Expand Down Expand Up @@ -139,5 +140,4 @@ const FadedScrollView = (props: Props) => {
};

FadedScrollView.displayName = 'IGNORE';
// @ts-expect-error
export default forwardRef<FadedScrollViewProps, Statics>(FadedScrollView);
export default forwardRef<FadedScrollViewProps, ComponentStatics<FadedScrollViewProps>, FadedScrollViewRef>(FadedScrollView);
4 changes: 3 additions & 1 deletion src/components/icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import isUndefined from 'lodash/isUndefined';
import React, {useMemo, forwardRef} from 'react';
import {Image, ImageProps, StyleSheet} from 'react-native';
import {asBaseComponent, BaseComponentInjectedProps, MarginModifiers, Constants} from '../../commons/new';
import {ComponentStatics} from '../../typings/common';
import {getAsset, isSvg, isBase64ImageContent} from '../../utils/imageUtils';
import {RecorderProps} from '../../typings/recorderTypes';
import SvgImage from '../svgImage';
Expand Down Expand Up @@ -89,7 +90,8 @@ Icon.displayName = 'Icon';
Icon.defaultProps = {
assetGroup: 'icons'
};
export default asBaseComponent<IconProps, typeof Icon>(Icon, {modifiersOptions: {margins: true}});

export default asBaseComponent<IconProps, ComponentStatics<typeof Icon>>(Icon, {modifiersOptions: {margins: true}});

const styles = StyleSheet.create({
rtlFlipped: {
Expand Down
5 changes: 3 additions & 2 deletions src/components/pageControl/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from 'lodash';
import React, {PureComponent} from 'react';
import {StyleSheet, LayoutAnimation, StyleProp, ViewStyle} from 'react-native';
import {asBaseComponent, forwardRef} from '../../commons/new';
import {asBaseComponent} from '../../commons/new';
import {Colors} from '../../style';
import TouchableOpacity, {TouchableOpacityProps} from '../touchableOpacity';
import View from '../view';
Expand Down Expand Up @@ -239,7 +239,8 @@ class PageControl extends PureComponent<PageControlProps, State> {
}
}

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

const styles = StyleSheet.create({
container: {
Expand Down
3 changes: 2 additions & 1 deletion src/components/scrollBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import {ScrollView, FlatList} from 'react-native-gesture-handler';
import {Colors} from '../../style';
import {Constants, asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import {ComponentStatics} from '../../typings/common';
import View from '../view';
import Image from '../image';

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

Item.displayName = 'IGNORE';
ScrollBar.Item = Item;
export default asBaseComponent<ScrollBarProps, typeof ScrollBar>(forwardRef(ScrollBar));
export default asBaseComponent<ScrollBarProps, ComponentStatics<typeof ScrollBar>>(forwardRef(ScrollBar));
5 changes: 3 additions & 2 deletions src/components/slider/GradientSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {useCallback, useEffect, useState} from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import {Colors} from '../../style';
import {asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import {ComponentStatics} from '../../typings/common';
import Slider, {SliderProps} from './index';
import {Slider as NewSlider} from '../../incubator';
import {SliderContextProps} from './context/SliderContext';
Expand Down Expand Up @@ -192,7 +193,6 @@ const GradientSlider = (props: Props) => {
return (
<SliderComponent
{...others}
//@ts-expect-error
ref={forwardedRef}
onReset={reset}
renderTrack={renderTrack}
Expand All @@ -213,4 +213,5 @@ GradientSlider.displayName = 'GradientSlider';
GradientSlider.types = GradientSliderTypes;

// eslint-disable-next-line max-len
export default asBaseComponent<GradientSliderProps, typeof GradientSlider>(forwardRef(asSliderGroupChild(forwardRef(GradientSlider))));
// @ts-expect-error
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why we have an error here?
If it's too complicated we can solve it another time..

export default asBaseComponent<GradientSliderProps, ComponentStatics<typeof GradientSlider>>(forwardRef(asSliderGroupChild(forwardRef(GradientSlider))));
5 changes: 2 additions & 3 deletions src/components/tabController/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '../../commons/new';
import View from '../view';
import {Colors, Spacings, Typography} from '../../style';
import FadedScrollView from '../fadedScrollView';
import FadedScrollView, {FadedScrollViewRef} from '../fadedScrollView';
import {FaderProps} from '../fader';
import useScrollToItem from './useScrollToItem';
import {useDidUpdate} from 'hooks';
Expand Down Expand Up @@ -161,7 +161,7 @@ const TabBar = (props: Props) => {
testID
} = props;

const tabBar = useRef<typeof FadedScrollView>();
const tabBar = useRef<FadedScrollViewRef>(null);
const [key, setKey] = useState<string>(generateKey(Constants.orientation, labelColor, selectedLabelColor));
const context = useContext(TabBarContext);
const {items: contextItems, currentPage, targetPage, containerWidth: contextContainerWidth} = context;
Expand Down Expand Up @@ -295,7 +295,6 @@ const TabBar = (props: Props) => {
return (
<View style={_containerStyle} key={key} bg-$backgroundElevated>
<FadedScrollView
// @ts-expect-error
ref={tabBar}
horizontal
showsHorizontalScrollIndicator={false}
Expand Down
2 changes: 1 addition & 1 deletion src/components/text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface HighlightStringProps {

export type HighlightString = string | HighlightStringProps;

export type TextProps = RNTextProps &
export type TextProps = Omit<RNTextProps, 'style'> &
TypographyModifiers &
ColorsModifiers &
MarginModifiers &
Expand Down
2 changes: 1 addition & 1 deletion src/components/textField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export {
ValidationMessagePositionType as TextFieldValidationMessagePositionType,
MandatoryIndication as TextFieldMandatoryIndication
};
export default asBaseComponent<TextFieldProps, StaticMembers>(forwardRef(TextField as any), {
export default asBaseComponent<TextFieldProps, StaticMembers, TextFieldRef>(forwardRef(TextField as any), {
modifiersOptions: {
margins: true,
paddings: true,
Expand Down
9 changes: 4 additions & 5 deletions src/incubator/Slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from './SliderPresenter';
import Thumb from './Thumb';
import Track from './Track';

import {ComponentStatics} from '../../typings/common';
export interface SliderProps extends AccessibilityProps {
/**
* Initial value
Expand Down Expand Up @@ -131,8 +131,8 @@ export interface SliderProps extends AccessibilityProps {
migrate?: boolean;
}

type Props = SliderProps & ForwardRefInjectedProps;
interface Statics {
type Props = SliderProps & ForwardRefInjectedProps<SliderRef>;
export interface SliderRef {
reset: () => void;
}

Expand Down Expand Up @@ -398,8 +398,7 @@ const Slider = React.memo((props: Props) => {
);
});

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

const styles = StyleSheet.create({
container: {
Expand Down
2 changes: 1 addition & 1 deletion src/incubator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export {
export {default as Toast, ToastProps, ToastPresets} from './toast';
export {default as TouchableOpacity, TouchableOpacityProps} from './TouchableOpacity';
export {default as PanView, PanViewProps, PanViewDirections, PanViewDismissThreshold} from './panView';
export {default as Slider} from './Slider';
export {default as Slider, SliderRef} from './Slider';
export {default as Dialog, DialogProps, DialogHeaderProps, DialogStatics, DialogImperativeMethods} from './Dialog';
// TODO: delete exports after fully removing from private
export {default as ChipsInput, ChipsInputProps, ChipsInputChangeReason, ChipsInputChipProps} from '../components/chipsInput';
Expand Down
1 change: 0 additions & 1 deletion src/incubator/toast/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ const Toast = (props: PropsWithChildren<ToastProps>) => {
<View accessible={Constants.isIOS} style={styles.messageContainer}>
<Text
testID={`${testID}-message`}
// @ts-expect-error
ref={viewRef}
style={[styles.message, {textAlign}, messageStyle]}
accessibilityLabel={toastPreset.accessibilityMessage}
Expand Down
2 changes: 2 additions & 0 deletions src/typings/common.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export type ExtendTypeWith<T extends Constructor<any>, OtherObject extends objec
ConstructorParameters<T>
>;
export type Dictionary<TYPE> = {[key: string]: TYPE};

export type ComponentStatics<T> = {[Key in keyof T]: T[Key]}