Skip to content

Commit 01e7a3a

Browse files
committed
WIP
1 parent ebd3a5b commit 01e7a3a

6 files changed

Lines changed: 49 additions & 123 deletions

File tree

shared/chat/routes.tsx

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {useModalHeaderState} from '@/stores/modal-header'
1111
import {ModalTitle} from '@/teams/common'
1212
import inboxGetOptions from './inbox/get-options'
1313
import inboxAndConvoGetOptions from './inbox-and-conversation-get-options'
14-
import {defineRouteMap, withRouteParams} from '@/constants/types/router'
14+
import {defineRouteMap} from '@/constants/types/router'
1515
import type {BlockModalContext} from './blocking/block-modal'
1616
const Convo = React.lazy(async () => import('./conversation/container'))
1717

@@ -153,15 +153,15 @@ export const newRoutes = defineRouteMap({
153153
})
154154

155155
export const newModalRoutes = defineRouteMap({
156-
chatAddToChannel: withRouteParams<ChatAddToChannelRouteParams>(Chat.makeChatScreen(
156+
chatAddToChannel: Chat.makeChatScreen(
157157
React.lazy(async () => import('./conversation/info-panel/add-to-channel')),
158158
{
159159
getOptions: ({route}) => ({
160160
headerRight: () => <AddToChannelHeaderRight />,
161161
headerTitle: () => <AddToChannelHeaderTitle teamID={route.params.teamID} />,
162162
}),
163163
}
164-
)),
164+
),
165165
chatAttachmentFullscreen: Chat.makeChatScreen(
166166
React.lazy(async () => import('./conversation/attachment-fullscreen/screen')),
167167
{
@@ -178,24 +178,22 @@ export const newModalRoutes = defineRouteMap({
178178
React.lazy(async () => import('./conversation/attachment-get-titles')),
179179
{getOptions: {modalStyle: {height: 660, maxHeight: 660}}}
180180
),
181-
chatBlockingModal: withRouteParams<ChatBlockingRouteParams>({
181+
chatBlockingModal: {
182182
...Chat.makeChatScreen(React.lazy(async () => import('./blocking/block-modal')), {
183183
getOptions: {
184184
headerTitle: () => <Kb.Icon type="iconfont-user-block" sizeType="Big" color={Kb.Styles.globalColors.red} />,
185185
},
186186
}),
187187
initialParams: emptyChatBlockingRouteParams,
188-
}),
188+
},
189189
chatChooseEmoji: Chat.makeChatScreen(React.lazy(async () => import('./emoji-picker/container')), {
190190
getOptions: {headerShown: false},
191191
}),
192192
chatConfirmNavigateExternal: Chat.makeChatScreen(
193193
React.lazy(async () => import('./punycode-link-warning')),
194194
{skipProvider: true}
195195
),
196-
chatConfirmRemoveBot: withRouteParams<ChatConfirmRemoveBotRouteParams>(
197-
Chat.makeChatScreen(React.lazy(async () => import('./conversation/bot/confirm')), {canBeNullConvoID: true})
198-
),
196+
chatConfirmRemoveBot: Chat.makeChatScreen(React.lazy(async () => import('./conversation/bot/confirm')), {canBeNullConvoID: true}),
199197
chatCreateChannel: Chat.makeChatScreen(
200198
React.lazy(async () => import('./create-channel')),
201199
{skipProvider: true}
@@ -208,7 +206,7 @@ export const newModalRoutes = defineRouteMap({
208206
React.lazy(async () => import('./conversation/info-panel')),
209207
{getOptions: C.isMobile ? undefined : {modalStyle: {height: '80%', width: '80%'}}}
210208
),
211-
chatInstallBot: withRouteParams<ChatInstallBotRouteParams>(Chat.makeChatScreen(
209+
chatInstallBot: Chat.makeChatScreen(
212210
React.lazy(async () => import('./conversation/bot/install')),
213211
{
214212
getOptions: {
@@ -218,7 +216,7 @@ export const newModalRoutes = defineRouteMap({
218216
},
219217
skipProvider: true,
220218
}
221-
)),
219+
),
222220
chatInstallBotPick: Chat.makeChatScreen(
223221
React.lazy(async () => import('./conversation/bot/team-picker')),
224222
{getOptions: {title: 'Add to team or chat'}, skipProvider: true}
@@ -242,13 +240,13 @@ export const newModalRoutes = defineRouteMap({
242240
overlayStyle: {alignSelf: 'stretch'},
243241
}),
244242
}),
245-
chatSearchBots: withRouteParams<ChatSearchBotsRouteParams>({
243+
chatSearchBots: {
246244
...Chat.makeChatScreen(React.lazy(async () => import('./conversation/bot/search')), {
247245
canBeNullConvoID: true,
248246
getOptions: {title: 'Add a bot'},
249247
}),
250248
initialParams: emptyChatSearchBotsRouteParams,
251-
}),
249+
},
252250
chatSendToChat: Chat.makeChatScreen(
253251
React.lazy(async () => import('./send-to-chat')),
254252
{
@@ -259,10 +257,10 @@ export const newModalRoutes = defineRouteMap({
259257
skipProvider: true,
260258
}
261259
),
262-
chatShowNewTeamDialog: withRouteParams<ChatShowNewTeamDialogRouteParams>({
260+
chatShowNewTeamDialog: {
263261
...Chat.makeChatScreen(React.lazy(async () => import('./new-team-dialog-container'))),
264262
initialParams: emptyChatShowNewTeamDialogRouteParams,
265-
}),
263+
},
266264
chatUnfurlMapPopup: Chat.makeChatScreen(
267265
React.lazy(async () => import('./conversation/messages/text/unfurl/unfurl-list/map-popup')),
268266
{getOptions: {title: 'Location'}}

shared/constants/types/router.tsx

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,38 +84,19 @@ export type GetOptions<Screen extends AnyScreen = AnyScreen> =
8484
| GetOptionsRet
8585
| ((p: React.ComponentProps<Screen>) => GetOptionsRet)
8686

87-
export type RouteDef<
88-
Screen extends AnyScreen = AnyScreen,
89-
Params = ScreenRouteParams<Screen>,
90-
> = {
87+
export type RouteDef<Screen extends AnyScreen = AnyScreen, Params = ScreenRouteParams<Screen>> = {
9188
__routeParams?: Params
9289
getOptions?: GetOptions<Screen>
93-
initialParams?: Params extends undefined ? undefined : Params
90+
initialParams?: Params
9491
screen: Screen
9592
}
9693
export type RouteMap = {[K in string]?: RouteDef}
9794

98-
type RouteDefMatchesScreen<R> =
99-
R extends {screen: infer Screen}
100-
? Screen extends AnyScreen
101-
? Omit<R, '__routeParams' | 'getOptions' | 'initialParams' | 'screen'> & {
102-
__routeParams?: R extends {__routeParams?: infer Params} ? Params : ScreenRouteParams<Screen>
103-
getOptions?: GetOptions<Screen>
104-
initialParams?: (R extends {__routeParams?: infer Params} ? Params : ScreenRouteParams<Screen>) extends undefined
105-
? undefined
106-
: R extends {__routeParams?: infer Params}
107-
? Params
108-
: ScreenRouteParams<Screen>
109-
screen: Screen
110-
}
111-
: never
112-
: never
113-
: never
114-
115-
export const defineRouteMap = <const Routes extends Record<string, {screen: AnyScreen}>>(
116-
routes: Routes & {[K in keyof Routes]: RouteDefMatchesScreen<Routes[K]>}
117-
) => routes
95+
export const defineRouteMap = <const Routes,>(routes: Routes) => routes
11896

119-
export const withRouteParams = <Params, Screen extends AnyScreen>(
97+
// tsgo does not support partial type argument application: providing Params explicitly
98+
// while letting Screen be inferred causes "Expected 2 type arguments, but got 1".
99+
// Adding Screen = AnyScreen as a default fixes this.
100+
export const withRouteParams = <Params, Screen extends AnyScreen = AnyScreen>(
120101
route: RouteDef<Screen>
121102
): RouteDef<Screen, Params> => route as RouteDef<Screen, Params>

shared/login/routes.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import {newRoutes as provisionRoutes} from '../provision/routes-sub'
66
import {sharedNewRoutes as settingsRoutes} from '../settings/routes'
77
import {newRoutes as signupRoutes} from './signup/routes'
88
import {settingsFeedbackTab} from '@/constants/settings'
9-
import {defineRouteMap, withRouteParams} from '@/constants/types/router'
10-
import type {Props as FeedbackRouteParams} from '../settings/feedback/container'
9+
import {defineRouteMap} from '@/constants/types/router'
1110

1211
const recoverPasswordStyles = Kb.Styles.styleSheetCreate(() => ({
1312
questionBox: Kb.Styles.padding(Kb.Styles.globalMargins.tiny, Kb.Styles.globalMargins.tiny, 0),
@@ -26,7 +25,7 @@ const recoverPasswordGetOptions = {
2625
}
2726

2827
export const newRoutes = defineRouteMap({
29-
feedback: withRouteParams<FeedbackRouteParams>(settingsRoutes[settingsFeedbackTab]),
28+
feedback: settingsRoutes[settingsFeedbackTab],
3029
login: {getOptions: {headerShown: false}, screen: React.lazy(async () => import('.'))},
3130
recoverPasswordDeviceSelector: {
3231
getOptions: {title: 'Recover password'},

shared/router-v2/route-params.tsx

Lines changed: 18 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,24 @@
1-
import type * as React from 'react'
21
import type {RouteProp} from '@react-navigation/native'
32
import type {NativeStackNavigationProp} from '@react-navigation/native-stack'
4-
import type {RouteDef} from '@/constants/types/router'
5-
import type {newRoutes as chatNewRoutes, newModalRoutes as chatNewModalRoutes} from '../chat/routes'
6-
import type {newRoutes as cryptoNewRoutes, newModalRoutes as cryptoNewModalRoutes} from '../crypto/routes'
7-
import type {newRoutes as deviceNewRoutes, newModalRoutes as deviceNewModalRoutes} from '../devices/routes'
8-
import type {newRoutes as fsNewRoutes, newModalRoutes as fsNewModalRoutes} from '../fs/routes'
9-
import type {newRoutes as gitNewRoutes, newModalRoutes as gitNewModalRoutes} from '../git/routes'
10-
import type {newRoutes as loginNewRoutes, newModalRoutes as loginNewModalRoutes} from '../login/routes'
11-
import type {newRoutes as peopleNewRoutes, newModalRoutes as peopleNewModalRoutes} from '../people/routes'
12-
import type {newRoutes as profileNewRoutes, newModalRoutes as profileNewModalRoutes} from '../profile/routes'
13-
import type {
14-
newRoutes as settingsNewRoutes,
15-
newModalRoutes as settingsNewModalRoutes,
16-
} from '../settings/routes'
17-
import type {newRoutes as signupNewRoutes, newModalRoutes as signupNewModalRoutes} from '../signup/routes'
18-
import type {newRoutes as teamsNewRoutes, newModalRoutes as teamsNewModalRoutes} from '../teams/routes'
19-
import type {newModalRoutes as walletsNewModalRoutes} from '../wallets/routes'
20-
import type {newModalRoutes as incomingShareNewModalRoutes} from '../incoming-share/routes'
3+
import type {routes, modalRoutes, loggedOutRoutes} from './routes'
214

22-
type IsUnknown<T> = unknown extends T ? ([keyof T] extends [never] ? true : false) : false
23-
type NormalizeParams<T> = IsUnknown<T> extends true ? undefined : T extends object | undefined ? T : undefined
24-
type ExtractScreenParams<Screen> =
25-
Screen extends React.LazyExoticComponent<infer Inner>
26-
? ExtractScreenParams<Inner>
27-
: Screen extends React.ComponentType<infer Props>
28-
? Props extends {route: {params: infer Params}}
29-
? NormalizeParams<Params>
30-
: Props extends {route: {params?: infer Params}}
31-
? NormalizeParams<Params>
32-
: undefined
33-
: undefined
34-
type ExtractRouteParams<Route> = Route extends RouteDef<any, infer Params>
35-
? NormalizeParams<Params>
36-
: Route extends {initialParams: infer Params}
37-
? NormalizeParams<Params>
38-
: '__routeParams' extends keyof Route
39-
? Route extends {__routeParams?: infer Params}
40-
? NormalizeParams<Params>
5+
// tsgo bug: StaticParamList is the idiomatic React Navigation equivalent of _ExtractParams,
6+
// but tsgo reports "TS2315: Type 'StaticParamList' is not generic" (works fine with regular tsc).
7+
// Once tsgo fixes re-exported generic type aliases, replace _ExtractParams:
8+
// type _SyntheticConfig = {readonly config: {readonly screens: _AllScreens}}
9+
// export type RootParamList = StaticParamList<_SyntheticConfig> & Tabs & {...}
10+
//
11+
// Similarly, avoid matching on RouteDef<any, infer Params> — tsgo fails to infer Params
12+
// through conditional types in RouteDef's field definitions. Instead, extract params
13+
// directly from the screen function's route prop, which tsgo handles correctly.
14+
type _ExtractParams<T> = {
15+
[K in keyof T]: T[K] extends {screen: infer U}
16+
? U extends (args: infer V) => any
17+
? V extends {route: {params: infer W}}
18+
? W
19+
: undefined
4120
: undefined
42-
: Route extends {screen: infer Screen}
43-
? ExtractScreenParams<Screen>
4421
: undefined
45-
46-
type _ExtractParams<T> = {
47-
[K in keyof T]: ExtractRouteParams<T[K]>
4822
}
4923

5024
type Tabs = {
@@ -62,34 +36,10 @@ type Tabs = {
6236
'tabs.walletsTab': undefined
6337
}
6438

65-
type _AllScreens = typeof deviceNewRoutes &
66-
typeof chatNewRoutes &
67-
typeof cryptoNewRoutes &
68-
typeof peopleNewRoutes &
69-
typeof profileNewRoutes &
70-
typeof fsNewRoutes &
71-
typeof settingsNewRoutes &
72-
typeof teamsNewRoutes &
73-
typeof gitNewRoutes &
74-
typeof chatNewModalRoutes &
75-
typeof cryptoNewModalRoutes &
76-
typeof deviceNewModalRoutes &
77-
typeof fsNewModalRoutes &
78-
typeof gitNewModalRoutes &
79-
typeof loginNewModalRoutes &
80-
typeof peopleNewModalRoutes &
81-
typeof profileNewModalRoutes &
82-
typeof settingsNewModalRoutes &
83-
typeof signupNewModalRoutes &
84-
typeof teamsNewModalRoutes &
85-
typeof walletsNewModalRoutes &
86-
typeof incomingShareNewModalRoutes &
87-
typeof loginNewRoutes &
88-
typeof signupNewRoutes
39+
type _AllScreens = typeof routes & typeof modalRoutes & typeof loggedOutRoutes
8940

90-
type KeybaseRootParamList = _ExtractParams<_AllScreens> &
41+
export type RootParamList = _ExtractParams<_AllScreens> &
9142
Tabs & {loading: undefined; loggedOut: undefined; loggedIn: undefined}
92-
export type RootParamList = KeybaseRootParamList
9343

9444
export type RouteKeys = keyof RootParamList
9545
export type NoParamRouteKeys = {

shared/settings/routes.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {newRoutes as devicesRoutes} from '../devices/routes'
55
import {newRoutes as gitRoutes} from '../git/routes'
66
import {newRoutes as walletsRoutes} from '../wallets/routes'
77
import * as Settings from '@/constants/settings'
8-
import {defineRouteMap, withRouteParams} from '@/constants/types/router'
8+
import {defineRouteMap} from '@/constants/types/router'
99
import {usePushState} from '@/stores/push'
1010
import {usePWState} from '@/stores/settings-password'
1111
import {e164ToDisplay} from '@/util/phone-numbers'
@@ -74,14 +74,12 @@ const ManageContactsScreen: React.ComponentType =
7474
C.isMobile ? React.lazy(async () => import('./manage-contacts')) : EmptySettingsScreen
7575
const emptyFeedbackParams: FeedbackRouteParams = {}
7676

77-
const feedback = withRouteParams<FeedbackRouteParams>(
78-
{
79-
...C.makeScreen(React.lazy(async () => import('./feedback/container')), {
80-
getOptions: C.isMobile ? {headerShown: true, title: 'Feedback'} : {},
81-
}),
82-
initialParams: emptyFeedbackParams,
83-
}
84-
)
77+
const feedback = {
78+
...C.makeScreen(React.lazy(async () => import('./feedback/container')), {
79+
getOptions: C.isMobile ? {headerShown: true, title: 'Feedback'} : {},
80+
}),
81+
initialParams: emptyFeedbackParams,
82+
}
8583

8684
export const sharedNewRoutes = defineRouteMap({
8785
[Settings.settingsAboutTab]: {

shared/teams/routes.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import contactRestricted from '../team-building/contact-restricted.page'
1010
import teamsTeamBuilder from '../team-building/page'
1111
import {useModalHeaderState} from '@/stores/modal-header'
1212
import teamsRootGetOptions from './get-options'
13-
import {defineRouteMap, withRouteParams} from '@/constants/types/router'
13+
import {defineRouteMap} from '@/constants/types/router'
1414

1515
type TeamRouteParams = {
1616
teamID: T.Teams.TeamID
@@ -192,10 +192,10 @@ const NewTeamInfoHeaderLeft = () => {
192192
}
193193

194194
export const newRoutes = defineRouteMap({
195-
team: withRouteParams<TeamRouteParams>(C.makeScreen(
195+
team: C.makeScreen(
196196
React.lazy(async () => import('./team')),
197197
{getOptions: {headerShadowVisible: false, headerTitle: ''}}
198-
)),
198+
),
199199
teamChannel: Chat.makeChatScreen(
200200
React.lazy(async () => import('./channel')),
201201
{getOptions: {headerShadowVisible: false, headerTitle: ''}}

0 commit comments

Comments
 (0)