// ---- Base Types ---- type Specifiers = { s: string; d: number; f: number; }; type S = keyof Specifiers; // ---- Tuple Math Utilities ---- // Builds a tuple of length L type BuildTuple = T['length'] extends L ? T : BuildTuple; // Adds two numbers by building and merging tuples type Add = [ ...BuildTuple, ...BuildTuple, ]['length'] extends infer R extends number ? R : never; // --- Escaped Percent Handling ---- // Removes escaped double-percent (%%) sequences from a format string type StripEscapedPercents = T extends `${infer Head}%%${infer Tail}` ? `${Head}${StripEscapedPercents}` : T; // ---- Specifier Utilities ---- // Checks if a character is a valid format specifier type IsValidSpec = C extends S ? C : never; // ---- Format Specifier Parsing ---- // Parses precision and format specifier, supports dynamic precision (e.g. %.*f) type ParsePrecisionAndSpec = T extends `.*${infer RawSpec}${infer Rest}` ? IsValidSpec extends infer Spec extends S ? ['.*', Spec, Rest] : never : T extends `0.${infer PrecisionAndSpec}${infer RestAfterDigits}` ? PrecisionAndSpec extends `${number}` ? RestAfterDigits extends `${infer RawSpec}${infer Rest}` ? IsValidSpec extends infer Spec extends S ? [`.${PrecisionAndSpec}`, Spec, Rest] : never : never : never : T extends `.${infer PrecisionAndSpec}${infer RestAfterDigits}` ? PrecisionAndSpec extends `${number}` ? RestAfterDigits extends `${infer RawSpec}${infer Rest}` ? IsValidSpec extends infer Spec extends S ? [`.${PrecisionAndSpec}`, Spec, Rest] : never : never : never : T extends `${infer RawSpec}${infer Rest}` ? IsValidSpec extends infer Spec extends S ? ['', Spec, Rest] : never : never; // ---- Positional Placeholder Parsing ---- // Recursively collects all positional placeholders and their expected types type CollectPositionalPlaceholders< T extends string, Collected extends Record = {}, > = StripEscapedPercents extends `${infer _}%${infer PosStr}$${infer AfterPos}` ? PosStr extends `${number}` ? ParsePrecisionAndSpec extends [ infer Precision extends string, infer Spec extends S, infer Rest extends string, ] ? IsValidSpec extends never ? never : Precision extends '.*' ? CollectPositionalPlaceholders< Rest, Collected & { [K in PosStr]: [number, Specifiers[Spec]] } > : CollectPositionalPlaceholders< Rest, Collected & { [K in PosStr]: Specifiers[Spec] } > : CollectPositionalPlaceholders : Collected : Collected; // ---- Positional Argument Extraction ---- // Gets the max index used in positional placeholders type GetMaxPosition> = { [K in keyof T]: K extends `${infer N extends number}` ? N : never; }[keyof T]; // Computes max of a number by building up a tuple type Max = [N] extends [ Partial['length'], ] ? A['length'] : Max; // Builds a final tuple of arguments from the collected positional types type BuildPositionalTuple< Collected extends { [K: number]: any }, MaxPos extends number, CurrentPos extends number = 1, Result extends any[] = [], > = CurrentPos extends Add ? Result : `${CurrentPos}` extends keyof Collected ? Collected[CurrentPos] extends [any, any] ? BuildPositionalTuple< Collected, MaxPos, Add, [...Result, ...Collected[CurrentPos]] > : BuildPositionalTuple< Collected, MaxPos, Add, [...Result, Collected[CurrentPos]] > : BuildPositionalTuple< Collected, MaxPos, Add, [...Result, unknown] >; // Main positional argument extractor type ExtractPositionalPlaceholders = CollectPositionalPlaceholders extends infer Collected extends Record< string, any > ? keyof Collected extends never ? [] : Max> extends infer MaxPos extends number ? BuildPositionalTuple : [] : []; // ---- Unnamed Placeholder Extraction ---- // Extracts unnamed placeholders like %s, %.2f, %.*d (ignores positional/named) type ExtractUnnamedPlaceholders = StripEscapedPercents extends `${infer _}%${infer AfterPercent}` ? AfterPercent extends `${infer _Num extends `${number}`}$${infer AfterPositional}` ? ExtractUnnamedPlaceholders // Skip positional : ParsePrecisionAndSpec extends [ infer Precision extends string, infer Spec extends S, infer Rest extends string, ] ? [ ...(Precision extends '.*' ? [number, Specifiers[Spec]] : [Specifiers[Spec]]), ...ExtractUnnamedPlaceholders, ] : [] : []; // ---- Named Placeholder Extraction ---- // Extracts named placeholders like %(key)s, %(name).2f type ExtractNamedPlaceholders = StripEscapedPercents extends `${infer _}%(${infer Key})${infer AfterKey}` ? ParsePrecisionAndSpec extends [ infer Precision extends string, infer Spec extends S, infer Rest extends string, ] ? Precision extends '.*' ? never // Optional: disallow dynamic precision for named : { [K in Key]: Specifiers[Spec] } & ExtractNamedPlaceholders : {} : {}; // ---- Format Type Guards ---- // Checks if string has named placeholders type HasNamedPlaceholders = StripEscapedPercents extends `${infer _}%(${string})${string}` ? true : false; // Checks if string has positional placeholders type HasPositionalPlaceholders = StripEscapedPercents extends `${infer _Before}%${infer Rest}` ? Rest extends `${infer Index}$${infer _After}` ? Index extends `${number}` ? true : HasPositionalPlaceholders : HasPositionalPlaceholders : false; // Checks if string has unnamed placeholders type HasUnnamedPlaceholders = StripEscapedPercents extends `${infer _}%${infer Body}` ? Body extends `(${string})${string}` // Named — skip ? HasUnnamedPlaceholders : Body extends `${number}$${string}` // Positional — skip ? HasUnnamedPlaceholders : ParsePrecisionAndSpec extends [ infer _, infer Spec extends S, infer _, ] ? true : HasUnnamedPlaceholders : false; // ---- Public API ---- // Extracts the argument types required for a sprintf-like string export type SprintfArgs = HasNamedPlaceholders extends true ? HasPositionalPlaceholders extends true ? [never] // Invalid: named + positional : HasUnnamedPlaceholders extends true ? [never] // Invalid: named + unnamed : [values: ExtractNamedPlaceholders] : HasPositionalPlaceholders extends true ? HasUnnamedPlaceholders extends true ? [ ...ExtractPositionalPlaceholders, ...ExtractUnnamedPlaceholders, ] : ExtractPositionalPlaceholders : HasUnnamedPlaceholders extends true ? ExtractUnnamedPlaceholders : [];