Skip to content

Commit

Permalink
Merge pull request #40017 from software-mansion-labs/typescript/route…
Browse files Browse the repository at this point in the history
…s-validation

[TS Migration][No QA] Improve routes validation
  • Loading branch information
Julesssss authored Apr 11, 2024
2 parents 0f4da45 + 0becc8a commit 65129a1
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 13 deletions.
21 changes: 10 additions & 11 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {IsEqual, ValueOf} from 'type-fest';
import type {ValueOf} from 'type-fest';
import type CONST from './CONST';
import type {IOURequestType} from './libs/actions/IOU';
import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual';

// This is a file containing constants for all the routes we want to be able to go to

Expand Down Expand Up @@ -730,20 +731,18 @@ export default ROUTES;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ExtractRouteName<TRoute> = TRoute extends {getRoute: (...args: any[]) => infer TRouteName} ? TRouteName : TRoute;

type AllRoutes = {
/**
* Represents all routes in the app as a union of literal strings.
*/
type Route = {
[K in keyof typeof ROUTES]: ExtractRouteName<(typeof ROUTES)[K]>;
}[keyof typeof ROUTES];

type RouteIsPlainString = IsEqual<AllRoutes, string>;
type RoutesValidationError = 'Error: One or more routes defined within `ROUTES` have not correctly used `as const` in their `getRoute` function return value.';

/**
* Represents all routes in the app as a union of literal strings.
*
* If this type resolves to `never`, it implies that one or more routes defined within `ROUTES` have not correctly used
* `as const` in their `getRoute` function return value.
*/
type Route = RouteIsPlainString extends true ? never : AllRoutes;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type RouteIsPlainString = AssertTypesNotEqual<string, Route, RoutesValidationError>;

type HybridAppRoute = (typeof HYBRID_APP_ROUTES)[keyof typeof HYBRID_APP_ROUTES];

export type {Route, HybridAppRoute, AllRoutes};
export type {Route, HybridAppRoute};
4 changes: 2 additions & 2 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import * as TransactionUtils from '@libs/TransactionUtils';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {AllRoutes} from '@src/ROUTES';
import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {Participant} from '@src/types/onyx/IOU';
Expand Down Expand Up @@ -122,7 +122,7 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps &
isReadOnly?: boolean;

/** Depending on expense report or personal IOU report, respective bank account route */
bankAccountRoute?: AllRoutes;
bankAccountRoute?: Route;

/** The policyID of the request */
policyID?: string;
Expand Down
11 changes: 11 additions & 0 deletions src/types/utils/AssertTypesNotEqual.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type {IsEqual} from 'type-fest';

type MatchError = 'Error: Types do match';

/**
* The 'AssertTypesNotEqual' type here enforces that `T1` and `T2` do not match.
* If `T1` or `T2` are the same this type will cause a compile-time error.
*/
type AssertTypesNotEqual<T1, T2 extends IsEqual<T1, T2> extends false ? T1 : TMatchError, TMatchError = MatchError> = T1 & T2;

export default AssertTypesNotEqual;

0 comments on commit 65129a1

Please sign in to comment.