Last active
May 8, 2024 20:00
-
-
Save erikyo/3b0a67d55b97fbe8ec7dc8d5f310e9c4 to your computer and use it in GitHub Desktop.
Strongly typed sprintf (allows placeholders and named placeholders)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Specifiers = { | |
's': string, | |
'd': number, | |
'b': boolean, | |
'D': Date | |
}; | |
type S = keyof Specifiers; | |
type ExtractNamedPlaceholders<T extends string> = | |
T extends `${infer Start}%(${infer Key})${infer Spec}${infer Rest}` | |
? Spec extends S | |
? { [K in Key]: Specifiers[Spec]} & ExtractNamedPlaceholders<Rest> | |
: never | |
: {}; | |
type ExtractUnnamedPlaceholders<T extends string> = | |
T extends `${infer Start}%${infer Spec}${infer Rest}` | |
? Spec extends S | |
? [Specifiers[Spec], ...ExtractUnnamedPlaceholders<Rest>] | |
: never | |
: []; | |
type SprintfArgs<T extends string> = | |
ExtractUnnamedPlaceholders<T> extends never | |
? [values: ExtractNamedPlaceholders<T>] | |
: ExtractUnnamedPlaceholders<T>; | |
declare function sprintf<T extends string>( | |
format: T, | |
...values: SprintfArgs<T> | |
): string; | |
sprintf('this is a %s and it is %d years old, right?%b %D', 'erik', 20, true, new Date()); // ok, it checks for different types | |
sprintf('this is a %s and it is %b years old, right?%d %D', 'erik', 20, true, new Date()); // not ok, wrong type | |
sprintf('this is a %s and it is %b%b%b%byears old, right?%d %D', 'erik', 20, true, new Date()); // not ok, too many arguments | |
sprintf('Hello %s', 'John'); // ok | |
sprintf('Hello %s', 'John', 'Doe'); // not ok, too many arguments | |
sprintf('Hello %s', false); // not ok, wrong type | |
sprintf('Hello %s', false); // not ok, wrong type | |
sprintf("Ciao %(names)s", { names: "erik" }) // ok named placeholder | |
sprintf("Ciao %(names)s %(years)d", { names: "erik", years: 2 });// ok multiple named placeholder | |
sprintf("Ciao %(names)s %(years)d", { names: "erik", years: "2" });// not ok, wrong type |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment