CLI commands
rndl typegen
Generate typed deep links from your route table, so a wrong route or param fails tsc instead of shipping a broken link.
rndl typegen writes a TypeScript module into your app with a compile-time-checked
buildDeepLink and a typed useTypedParams hook, generated from your route table.
rndl typegen --out src/deeplinks.gen.ts --app-dir src/app # Expo Router
rndl typegen --out src/deeplinks.gen.ts --config src/navigation/linking.ts#linking # React Navigation
rndl typegen --out src/deeplinks.gen.ts --app-dir src/app --watch # regenerate on changeWhat you get
Given a route like /users/[id] (Expo Router) or /users/:id (React Navigation), the generated
module exports:
import { buildDeepLink, useTypedParams } from './deeplinks.gen';
// Build a link. The route and its params are checked at compile time.
const url = buildDeepLink('/users/[id]', { id: '42' });
// => 'myapp://users/42'
// Override the baked-in scheme when you need a universal link.
const web = buildDeepLink('/users/[id]', { id: '42' }, 'https://example.com');
// => 'https://example.com/users/42'
// Read the current screen's params, typed for the route.
const { id } = useTypedParams<'/users/[id]'>();
buildDeepLink('/users/[id]', {}); // compile error: missing 'id'A wrong route key, a missing required param, or a mistyped param value fails tsc, so a broken
deep link is caught before it ships.
Under the hood the module declares two interfaces keyed by route: DeepLinkRoutes (the params
buildDeepLink accepts; all values are strings because they go into the URL) and DeepLinkParams
(what useTypedParams returns, matching what the router actually hands your screen).
Semantics worth knowing
- Route keys are router-native: Expo Router uses the bracket form you author (
/users/[id],/posts/[...slug]); React Navigation keeps its colon patterns (/users/:id). - Catch-all params are one
a/b/cstring when you build a link, and astring[]when you read them back (matching what the router returns). - React Navigation params defined with a custom
parsefunction are typedunknown, since their runtime type is not knowable from the config. - The scheme baked into the module comes from
--scheme, or by default from yourapp.jsonscheme or linkingprefixes. Pass a prefix as the thirdbuildDeepLinkargument to override it per call. - The generated module imports its small runtime from
@deeplink-devtools/core, so add that as a dependency of your app:
npm install @deeplink-devtools/coreFlags
| Flag | Description |
|---|---|
--out <file> | Required. Where to write the generated module. |
--app-dir <dir> | Expo Router app directory to generate from. |
--config <module[#export]> | React Navigation linking module to generate from. |
--scheme <scheme> | Scheme or prefix baked into buildDeepLink. |
--watch | Watch the route source and regenerate on change. |
To keep the types honest in CI, commit the generated file and run tsc over a file that exercises
it; a route change that invalidates a call site then fails the build instead of a user's tap.