@tanstack/router-core
Version:
Modern and scalable routing for React applications
178 lines (177 loc) • 9.62 kB
TypeScript
import { RouteIds } from './routeInfo.js';
import { AnyRouter } from './router.js';
export type Awaitable<T> = T | Promise<T>;
export type NoInfer<T> = [T][T extends any ? 0 : never];
export type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue ? TYesResult : TNoResult;
export type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<TValue, TKey> & Required<Pick<TValue, TKey>>;
export type PickRequired<T> = {
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
};
export type PickOptional<T> = {
[K in keyof T as undefined extends T[K] ? K : never]: T[K];
};
export type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never;
export type Expand<T> = T extends object ? T extends infer O ? O extends Function ? O : {
[K in keyof O]: O[K];
} : never : T;
export type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
export type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft & keyof TRight extends never ? TRight : Omit<TRight, keyof TLeft & keyof TRight> & {
[K in keyof TLeft & keyof TRight]?: TRight[K];
};
export type IsUnion<T, U extends T = T> = (T extends any ? (U extends T ? false : true) : never) extends false ? false : true;
export type IsNonEmptyObject<T> = T extends object ? keyof T extends never ? false : true : false;
export type Assign<TLeft, TRight> = TLeft extends any ? TRight extends any ? IsNonEmptyObject<TLeft> extends false ? TRight : IsNonEmptyObject<TRight> extends false ? TLeft : keyof TLeft & keyof TRight extends never ? TLeft & TRight : Omit<TLeft, keyof TRight> & TRight : never : never;
export type IntersectAssign<TLeft, TRight> = TLeft extends any ? TRight extends any ? IsNonEmptyObject<TLeft> extends false ? TRight : IsNonEmptyObject<TRight> extends false ? TLeft : TRight & TLeft : never : never;
export type Timeout = ReturnType<typeof setTimeout>;
export type Updater<TPrevious, TResult = TPrevious> = TResult | ((prev?: TPrevious) => TResult);
export type NonNullableUpdater<TPrevious, TResult = TPrevious> = TResult | ((prev: TPrevious) => TResult);
export type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive ? never : TUnion;
export type PartialMergeAllObject<TUnion> = ExtractObjects<TUnion> extends infer TObj ? [TObj] extends [never] ? never : {
[TKey in TObj extends any ? keyof TObj : never]?: TObj extends any ? TKey extends keyof TObj ? TObj[TKey] : never : never;
} : never;
export type MergeAllPrimitive = ReadonlyArray<any> | number | string | bigint | boolean | symbol | undefined | null;
export type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive ? TUnion : TUnion extends object ? never : TUnion;
export type PartialMergeAll<TUnion> = ExtractPrimitives<TUnion> | PartialMergeAllObject<TUnion>;
export type Constrain<T, TConstraint, TDefault = TConstraint> = (T extends TConstraint ? T : never) | TDefault;
export type ConstrainLiteral<T, TConstraint, TDefault = TConstraint> = (T & TConstraint) | TDefault;
/**
* To be added to router types
*/
export type UnionToIntersection<T> = (T extends any ? (arg: T) => any : never) extends (arg: infer T) => any ? T : never;
/**
* Merges everything in a union into one object.
* This mapped type is homomorphic which means it preserves stuff! :)
*/
export type MergeAllObjects<TUnion, TIntersected = UnionToIntersection<ExtractObjects<TUnion>>> = [keyof TIntersected] extends [never] ? never : {
[TKey in keyof TIntersected]: TUnion extends any ? TUnion[TKey & keyof TUnion] : never;
};
export type MergeAll<TUnion> = MergeAllObjects<TUnion> | ExtractPrimitives<TUnion>;
export type ValidateJSON<T> = ((...args: Array<any>) => any) extends T ? unknown extends T ? never : 'Function is not serializable' : {
[K in keyof T]: ValidateJSON<T[K]>;
};
export type LooseReturnType<T> = T extends (...args: Array<any>) => infer TReturn ? TReturn : never;
export type LooseAsyncReturnType<T> = T extends (...args: Array<any>) => infer TReturn ? TReturn extends Promise<infer TReturn> ? TReturn : TReturn : never;
/**
* Return the last element of an array.
* Intended for non-empty arrays used within router internals.
*/
export declare function last<T>(arr: ReadonlyArray<T>): T | undefined;
/**
* Apply a value-or-updater to a previous value.
* Accepts either a literal value or a function of the previous value.
*/
export declare function functionalUpdate<TPrevious, TResult = TPrevious>(updater: Updater<TPrevious, TResult> | NonNullableUpdater<TPrevious, TResult>, previous: TPrevious): TResult;
export declare const nullReplaceEqualDeep: typeof replaceEqualDeep;
/**
* This function returns `prev` if `_next` is deeply equal.
* If not, it will replace any deeply equal children of `b` with those of `a`.
* This can be used for structural sharing between immutable JSON values for example.
* Do not use this with signals
*/
export declare function replaceEqualDeep<T>(prev: any, _next: T, _makeObj?: () => {}, _depth?: number): T;
export declare function isPlainObject(o: any): boolean;
/**
* Check if a value is a "plain" array (no extra enumerable keys).
*/
export declare function isPlainArray(value: unknown): value is Array<unknown>;
/**
* Perform a deep equality check with options for partial comparison and
* ignoring `undefined` values. Optimized for router state comparisons.
*/
export declare function deepEqual(a: any, b: any, opts?: {
partial?: boolean;
ignoreUndefined?: boolean;
}): boolean;
export type StringLiteral<T> = T extends string ? string extends T ? string : T : never;
export type ThrowOrOptional<T, TThrow extends boolean> = TThrow extends true ? T : T | undefined;
export type StrictOrFrom<TRouter extends AnyRouter, TFrom, TStrict extends boolean = true> = TStrict extends false ? {
from?: never;
strict: TStrict;
} : {
from: ConstrainLiteral<TFrom, RouteIds<TRouter['routeTree']>>;
strict?: TStrict;
};
export type ThrowConstraint<TStrict extends boolean, TThrow extends boolean> = TStrict extends false ? (TThrow extends true ? never : TThrow) : TThrow;
export type ControlledPromise<T> = Promise<T> & {
resolve: (value: T) => void;
reject: (value: any) => void;
status: 'pending' | 'resolved' | 'rejected';
value?: T;
};
/**
* Create a promise with exposed resolve/reject and status fields.
* Useful for coordinating async router lifecycle operations.
*/
export declare function createControlledPromise<T>(onResolve?: (value: T) => void): ControlledPromise<T>;
/**
* Heuristically detect dynamic import "module not found" errors
* across major browsers for lazy route component handling.
*/
export declare function isModuleNotFoundError(error: any): boolean;
export declare function isPromise<T>(value: Promise<Awaited<T>> | T): value is Promise<Awaited<T>>;
export declare function findLast<T>(array: ReadonlyArray<T>, predicate: (item: T) => boolean): T | undefined;
/**
* Default list of URL protocols to allow in links, redirects, and navigation.
* Any absolute URL protocol not in this list is treated as dangerous by default.
*/
export declare const DEFAULT_PROTOCOL_ALLOWLIST: string[];
/**
* Check if a URL string uses a protocol that is not in the allowlist.
* Returns true for blocked protocols like javascript:, blob:, data:, etc.
*
* The URL constructor correctly normalizes:
* - Mixed case (JavaScript: → javascript:)
* - Whitespace/control characters (java\nscript: → javascript:)
* - Leading whitespace
*
* For relative URLs (no protocol), returns false (safe).
*
* @param url - The URL string to check
* @param allowlist - Set of protocols to allow
* @returns true if the URL uses a protocol that is not allowed
*/
export declare function isDangerousProtocol(url: string, allowlist: Set<string>): boolean;
/**
* Escape HTML special characters in a string to prevent XSS attacks
* when embedding strings in script tags during SSR.
*
* This is essential for preventing XSS vulnerabilities when user-controlled
* content is embedded in inline scripts.
*/
export declare function escapeHtml(str: string): string;
export declare function decodePath(path: string): {
path: string;
handledProtocolRelativeURL: boolean;
};
/**
* Encodes a path the same way `new URL()` would, but without the overhead of full URL parsing.
*
* This function encodes:
* - Whitespace characters (spaces → %20, tabs → %09, etc.)
* - Non-ASCII/Unicode characters (emojis, accented characters, etc.)
*
* It preserves:
* - Already percent-encoded sequences (won't double-encode %2F, %25, etc.)
* - ASCII special characters valid in URL paths (@, $, &, +, etc.)
* - Forward slashes as path separators
*
* Used to generate proper href values for SSR without constructing URL objects.
*
* @example
* encodePathLikeUrl('/path/file name.pdf') // '/path/file%20name.pdf'
* encodePathLikeUrl('/path/日本語') // '/path/%E6%97%A5%E6%9C%AC%E8%AA%9E'
* encodePathLikeUrl('/path/already%20encoded') // '/path/already%20encoded' (preserved)
*/
export declare function encodePathLikeUrl(path: string): string;
/**
* Builds the dev-mode CSS styles URL for route-scoped CSS collection.
* Used by HeadContent components in all framework implementations to construct
* the URL for the `/@tanstack-start/styles.css` endpoint.
*
* @param basepath - The router's basepath (may or may not have leading slash)
* @param routeIds - Array of matched route IDs to include in the CSS collection
* @returns The full URL path for the dev styles CSS endpoint
*/
export declare function buildDevStylesUrl(basepath: string, routeIds: Array<string>): string;