React Native Modalfy
v3.x
v3.x
  • Getting started
  • Installation
  • πŸ€“Guides
    • Creating a stack
    • Opening & closing
    • Passing params
    • Triggering a callback
    • Type checking with TypeScript
    • Subscribing to events
    • Using outside React
    • Upgrading from v2.x
  • πŸ“šAPI Reference
    • Types
      • ModalStackConfig
      • ModalOptions
      • ModalProp
      • ModalComponentProp
      • ModalProps
      • ModalComponentWithOptions
    • ModalProvider
    • createModalStack
    • useModal
    • withModal
    • modalfy
  • πŸ“°Blog
    • Unveiling Modalfy v3
    • Announcing Modalfy v2
    • Stacks on stacks in React Native
    • Introducing a Modal Citizen
  • πŸ—ƒοΈOthers
    • Help
    • Contributing
    • Changelog
    • GitHub
Powered by GitBook
On this page
  • ModalStackConfig & ModalOptions
  • ModalProp
  • ModalComponentProp & ModalProps
  • ModalComponentWithOptions
  • Ease of life
  • Optional provisioning of params generic

Was this helpful?

  1. Guides

Type checking with TypeScript

PreviousTriggering a callbackNextSubscribing to events

Last updated 8 months ago

Was this helpful?

There are 6 main interfaces that you'll use throughout your experience with Modalfy:

  • - Interface of the modal stack configuration (needed once).

  • - Interface of the modal configuration options.

  • - Interface of the modal prop exposed by the library.

  • / - Interface of the modal prop exposed by the library (specifically for modal components).

  • - Interface that adds type support of the modalOptions property (specifically for Hooks modal components).

The 6th and last main interface will actually be provided by you, as Modalfy v2 brought support for modal params type. That interface is going to be used mainly by , and . But for now: let's see how to use the other interfaces we just mentioned.

Please refer to the section of the API reference to get a complete overview of each of these interfaces.

ModalStackConfig & ModalOptions

These interfaces should be the ones you use the less. They're the ones that will ensure the type safety of the 2 arguments . So if we were to reuse the same initial example we say in the , we'd now have:

./App.tsx
import React from 'react'
import {
  ModalOptions,
  ModalStackConfig,
  createModalStack,
  ModalProvider,
} from 'react-native-modalfy'

import Navigation from './navigation.ts'
import { ErrorModal } from './components/Modals.ts'

const modalConfig: ModalStackConfig = { ErrorModal }
const defaultOptions: ModalOptions = { backdropOpacity: 0.6 }

const stack = createModalStack(modalConfig, defaultOptions)

const App = () => (
  <ModalProvider stack={stack}>
    <Navigation />
  </ModalProvider>
)


export default App

And from there, the type checker will get to work and let you know if you're doing something wrong.

If you directly provide the 2 objects instead of using variables like so:

createModalStack({ ErrorModal }, { backdropOpacity: 0.6 })

No need to use these 2 interfaces ascreateModalStack()is already doing it under the hood.

ModalProp

  • If you're inside a modal component and not a "regular" component, you should use ModalComponentProp instead.

  • If you're using useModal() Hook, no need to employModalPropas the Hook itself will take care of all the typing. Simply provide your params interface to the Hook as such useModal<ModalStackParams>()(explained below).

  • The main and potentially only use case for ModalProp then is when you're using a Class component.

./components/PokedexCard.tsx
import React from 'react'
import { Text, TouchableOpacity, View } from 'react-native'
import { ModalProp, withModal } from 'react-native-modalfy'

import { ModalStackParams } from '../types/modals.ts'

interface OwnProps {
  pokemon: ModalStackParams['PokedexEntryModal']['name']
  type: ModalStackParams['PokedexEntryModal']['type']
  id: ModalStackParams['PokedexEntryModal']['id']
}

type Props = ModalProp<ModalStackParams, OwnProps>

class PokedexCard extends React.Component<Props> {
  onPress = () => {
    const {
      modal: { openModal },
      pokemon,
      type,
      id,
    } = this.props

    openModal('PokedexEntryModal', { id, name: pokemon, type })
  }

  render() {
    const { id, pokemon, type } = this.props
    return (
      <TouchableOpacity onPress={this.onPress}>
        <View>
          <Text>Nr. {id}Text>
          <Text>{pokemon}</Text>
          <Text>{type}</Text>
          <Text>Show more</Text>
        </View>
      </TouchableOpacity>
    )
  }
}

export default withModal(PokedexCard)
// ❌ Don't use ModalProp with the useModal() Hook. If you want to fully type it
// simply provide your params interface as such: useModal<ModalStackParams>() 
// (ModalStackParams is explained below).

#L5 with ModalStackParams. It's an interface you'll have to build that will represent the complete tree of your modals and the types their params are expecting.

From #L7 to #L11, we're letting TypeScript know that <PokedexCard/> expects 3 props that should comply with the types specified in ModalStackParams. We're doing this to ensure the type safety of these 3 props because we're using them L#24 to open 'PokedexEntryModal' and pass them as params.

If we were to write ModalStackParams, we can now guesstimate that it could look something like this a minima:

interface ModalStackParams {
  PokedexEntryModal: {
    name: string
    type: string
    id: number
  }
}

ModalComponentProp & ModalProps

ModalComponentProp/ModalProps should only be used with modal components (rendered by Modalfy)!

type Props = ModalComponentProp<
  ModalStackParams,
  void,
  'PokedexEntryModal',
>

If we reuse our PokΓ©dex example, first we'd need to define our ModalStackParams as explained at the end of the previous section.

./types/modals.ts
export interface ModalStackParams {
  PokedexEntryModal: {
    name: string
    type: string
    id: number
  }
}
./modals/PokedexEntryModal.tsx
import React from 'react'
import { ModalProps } from 'react-native-modalfy'

type Props = ModalProps<'PokedexEntryModal'>

const PokedexEntryModal = (props: Props) => {
  return (
    // ...
  )
}

export default PokedexEntryModal
./modals/PokedexEntryModal.tsx
import React from 'react'
import { ModalProps } from 'react-native-modalfy'

type Props = ModalProps<'PokedexEntryModal'>

class PokedexEntryModal extends React.Component<Props> {
  render() {
    return (
      // ...
    )
  }
}

export default PokedexEntryModal
type Props = ModalProps<'PokedexEntryModal' | 'FavouritePokemonModal'>
./modals/PokedexEntryModal.tsx
// ...

import { connect } from 'react-redux'

// ...

import { ReduxState } from '../types/redux.ts'

interface OwnProps {
  favouritePokemon: ReduxState['user']['favouritePokemon']
}

type Props = ModalProps<'PokedexEntryModal', OwnProps>

class PokedexEntryModal extends React.Component<Props> {
  //...
}

const mapStateToProps = (state: ReduxState): OwnProps => {
  favouritePokemon: state.user.favouritePokemon
}

export default connect(mapStateToProps)(PokedexEntryModal)

ModalComponentWithOptions

ModalComponentWithOptions is only meant to be used with Hooks modal components. If you're working with classes, simply use the staticmodalOptionsproperty as explained below.

./modals/PokedexEntryModal.tsx
import React from 'react'
import { ModalComponentWithOptions, ModalProps } from 'react-native-modalfy'

import { ModalStackParams } from '../types/modals.ts'

type Props = ModalProps<'PokedexEntryModal'>

const PokedexEntryModal: ModalComponentWithOptions<Props> = () => {
  return (
    // ...
  )
}

PokedexEntryModal.modalOptions = {
  backdropColor = "rebeccapurple"
}

export default PokedexEntryModal

Notice howModalComponentWithOptions<Props> is used right after the modal variable name, not inside the parenthesis of the arrow function!

./modals/PokedexEntryModal.tsx
import React from 'react'
import {
  ModalComponentProp,
  ModalOptions
} from 'react-native-modalfy'

import { ModalStackParams } from '../types/modals.ts'

type Props = ModalComponentProp<
  ModalStackParams,
  void,
  'PokedexEntryModal',
>

class PokedexEntryModal extends React.Component<Props> {
  static modalOptions: ModalOptions = {
    backdropColor: 'rebeccapurple'
  }

  render() {
    return (
      // ...
    )
  }
}

export default PokedexEntryModal

Ease of life

Optional provisioning of params generic

Starting with v3.5.0 you're now able to omit to provide your equivalent of ModalStackParams to modalfy's methods. In order to do so:

  1. Declare your own ModalStackParams type:

./types/modals.ts
export type ModalStackParams = {
  AlertModal: { title: string; message: string };
};
  1. Create a react-native-modalfy.d.ts declaration file. Could be at the same file level where createModalStack is called and add:

./src/react-native-modalfy.d.ts
import 'react-native-modalfy';
import type { ModalStackParams } './types/modal.types';

declare module 'react-native-modalfy' {
  interface ModalfyCustomParams extends ModalStackParams {}
}
  1. Get full support of types out of the box:

./App.tsx
const AlertModal = () => {
  // No need to manually pass ModalStackParams anymore πŸ‘‡
-  const { openModal } = useModal<ModalStackParams>();
+  const { openModal } = useModal();

  const openDialog = () => {
    // Type checking/autocompleting still works well here πŸ‘‡
    openModal('AlertModal', { title: 'Hello', message: 'Welcome aboard!' });
  };
  // ...
}

This interface allows you to type check the modal prop that your regular component will get access to by using HOC. This means that you'll have to keep a few things in mind:

Now that we've covered the gotchas, let's see in action. In this example, we created a <PokedexCard/> component that's will open a modal with the full details about a specific Pokemon, with its name, type and entry number in the :

Lots of things are happening in this snippet, but if you're already familiar with , this should get you excited! Let's dissect this snippet.

You can have a look at the Example provided and available to see what ModalStackParamscould look like/be used in a real-world scenario.

You'd also realize that we didn't pass ModalStackParams as a generic to #L42, instead, we directly provided it to React.Component #L15, via Props created #L13. As you may know, with TypeScript, React.Component is a that accepts up to 2 arguments: React.Component<Props, State>. That's why ModalProp also accepts up to 2 arguments, your params interface and your component props and returns a type with your props type + the new modal prop. There are a few things to notice here:

If you have any State interface, you'll have to provide it to React.Component as a second argument, not .

If your component doesn't expect any props, you don't have to provide a second argument to ModalProp. If you want, you can even use it without providing the params type. This means that the most basic way of using is class PokedexCard extends React.Component<ModalProp>

On the contrary, providing your params types to gives you access to some sweet autocompleting experience (try to see what you get when you trigger it on for instance)!

These types work on the same principles as with just some key differences to keep in mind. The first and most important is:

If the component you're working on is not rendered by Modalfy directly/part of your config, you should use instead.

Given that we're in a specific modal component, accepts a 3rd argument, corresponding to the name of the modal the component you're writing represents:

But starting with v3.5.0, we now have a simplified version of ModalComponentProp named .

And then, our 'PokedexEntryModal' modal could look like this (granted ):

Given that you can reuse the same component for several modals, you can replace that 1st argument with a to make everything work.

Although you'll never manually render <PokedexEntryModal>yourself, / voluntarily expects props types as your modal component could be getting props from some HOCs. ie:

Please check out the /API reference to have an exhaustive list of what it brings with it.

As we saw in the guide, you have 3 different ways to provide options to a modal. While the first 2 are type-checked during the modal stack creation, only the 3rd one involves typing modalOptions from within the modal component itself.

To do so, simply pass your component props to and you're done! The interface will also directly take care of the fact that you're using it on a component, so no need to use React.FC with it. ie:

If you're working with a class, you'll just have to directly type the staticmodalOptions property with the same we used to type our modal stack. eg:

πŸ€“
ModalStackConfig
ModalOptions
ModalProp
ModalComponentProp
ModalProps
ModalComponentWithOptions
ModalProp
ModalComponentProp
modalfy()
Types
> ModalStackConfig API
> ModalOptions API
createModalStack()
Creating a stack section
> ModalProp API
withModal()
ModalProp
PokΓ©dex
TypeScript generics
in the repository
on Expo
withModal()
generic class
ModalProp
ModalProp
> ModalComponentProp API
> ModalProps API
ModalProp
createModalStack()
ModalProp
ModalComponentProp
ModalProps
union type
ModalComponentProp
ModalProps
ModalComponentProp
ModalProps
> ModalComponentWithOptions API
ModalComponentWithOptions
ModalOptions
you've properly set up your declaration file
ModalProp
Configuring a stack
openModal()