Initializing Text.defaultProps with Typescript

Viewed 2122

I just started rewriting my existing react-native project from js to typescript. To disable font scaling, I set Text.defaultProps.allowFontScaling to false at the beginning of App.js and it worked well.

import React from 'react';
import { Text } from 'react-native';
...

if (Text.defaultProps == null) Text.defaultProps = {};
Text.defaultProps.allowFontScaling=false; 

export default function App () {
  . . .
}

When I changed from App.js to App.tsx and ran tsc, I get following typescript error:

App.tsx:16:10 - error TS2339: Property 'defaultProps' does not exist on type 'typeof Text'.
16 if (Text.defaultProps == null) Text.defaultProps = {};

I tried to search similar issues and typescript documents but failed. How can I solve this error?

3 Answers

Want solutions to prevent font autoscaling in app.tsx?

import {Text, TextInput} from 'react-native';


interface TextWithDefaultProps extends Text {
    defaultProps?: { allowFontScaling?: boolean };
}

interface TextInputWithDefaultProps extends TextInput {
    defaultProps?: { allowFontScaling?: boolean };
}


((Text as unknown) as TextWithDefaultProps).defaultProps = ((Text as unknown) as TextWithDefaultProps).defaultProps || {};
((Text as unknown) as TextWithDefaultProps).defaultProps!.allowFontScaling = false;
((TextInput as unknown) as TextInputWithDefaultProps).defaultProps = ((TextInput as unknown) as TextInputWithDefaultProps).defaultProps || {};
((TextInput as unknown) as TextInputWithDefaultProps).defaultProps!.allowFontScaling = false;

const App = () => {
    ...
}

this Code actually working on my source

Are you using React Native Paper? You may be importing the wrong Text.

The following works, but I don't see these properties on the default React Native Text.

import { Text } from "react-native-paper";

if(Text.defaultProps == null) Text.defaultProps = {};
Text.defaultProps.allowFontScaling = false;

If this happens to be the case, you may have just discovered why TypeScript is useful.

However, the way I would do this is to actually just create a custom component that wraps the one I want to apply defaults too. Something like this that takes all the same props as the original and then I override them with some defaults.

import { FC } from 'react';
import { Text, TextProps } from 'react-native';

const defaultProps: TextProps = {
    allowFontScaling: false
}

const CustomText: FC<TextProps> = ({ children, ...props }) => {
    return <Text {...{ ...defaultProps, ...props }}>{children}</Text>
}

export default CustomText;

Then, I just use the custom component in the place of the one from the library.

function Component() {
    return <CustomText>Hello</CustomText>
}

Lastly, if you want to call these properties anyway. You can always cast the Text as any and the TypeScript compiler won't complain anymore.

import { Text } from 'react-native';

if ((Text as any).defaultProps == null) (Text as any).defaultProps = {};
(Text as any).defaultProps.allowFontScaling = false; 

@Todd Skelton's solution here helped me a lot, thank you, but I think the point can be made more concisely:

import { Text, TextProps } from 'react-native'
import React from 'react'
  
type ChildrenProps = {
  readonly children: React.ReactNode
}
 
export const TextWithoutOSScale = ({
  children,
  ...props
}: ChildrenProps & TextProps): React.ReactElement => {
  return (
    <Text allowFontScaling={false} {...props}>
      {children}
    </Text>
  )
}
Related