Skip to content

Memory leak when using recursive type with template literal #2917

@james-pre

Description

@james-pre

This is the same behavior/problem as microsoft/TypeScript#63197.

type Strip<Path extends string> = Path extends `${infer Rest}x` ? Strip<Rest> : Path;

Attempting to compile this single type results in a memory leak with no compiler error, eventually causing a system OOM.

tsconfig.json:

{
	"compilerOptions": {
		"lib": ["ESNext"],
		"module": "NodeNext",
		"target": "esnext",
		"moduleResolution": "NodeNext",
		"noImplicitThis": true,
		"noEmit": true,
		"declaration": true,
		"strict": true
	},
	"include": ["src/**/*.ts"],
	"exclude": ["node_modules"]
}

My use case is somewhat more complicated:

/**
 * Flatten an object structure into a set of "keys".
 *
 * @example
 * ```ts
 * type example = FlattenKeys<{ h: { s: { l: 1; v: 2 } } }>;
 * type result = "h" | "h.s" | "h.s.l" | "h.s.v";
 * ```
 */
export type FlattenKeys<O> = {
	[K in keyof O & (string | number)]: O[K] extends Record<any, any>
		? K | `${K}.${FlattenKeys<O[K]>}`
		: K;
}[O extends readonly any[]
	? keyof O & `${number}`
	: keyof O & (string | number)];

export type KeySeparator = '.' | '[' | ']';

/**
 * Get a value using a path of property keys.
 */
export type GetByString<
	Data,
	Path extends string | number = FlattenKeys<Data>,
> = Path extends `__proto__${`${KeySeparator}${string | number}` | ''}`
	? never
	: Path extends `${KeySeparator}${infer Rest}`
		? GetByString<Data, Rest>
		: Path extends `${infer Rest}${KeySeparator}`
			? GetByString<Data, Rest>
			: Path extends `${infer Key extends keyof Data & (string | number)}${KeySeparator}${infer Rest}`
				? GetByString<Data[Key], Rest>
				: Path extends keyof Data & (string | number)
					? Data[Path]
					: undefined;

interface Duck {
	taxonomy: {
		genus: 'anas';
		species: 'platyrhynchos';
	};
}

type DuckSpecies = GetByString<Duck, 'taxonomy.species'>; // 'platyrhynchos'

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions