00545-hard-printf

Back

type PrintTypeMap = {
  s: string;
  d: number;
};
type Format<T extends string> =
  T extends `${string}%${infer Letter}${infer Rest}`
    ? Letter extends keyof PrintTypeMap
      ? (arg: PrintTypeMap[Letter]) => Format<Rest>
      : Format<Rest>
    : string;

Solution by Vampirelee #32622

type Types<
	T extends string,
	V extends (string | number)[] = [],
> = T extends `${string}%${infer C}${infer L}`
	? Types<L, C extends "s" ? [...V, string] : C extends "d" ? [...V, number] : V>
	: V;

type Func<A, F = string> = A extends [...infer H, infer L] ? Func<H, (x: L) => F> : F;

type Format<T extends string> = Func<Types<T>>;

Solution by alexandroppolus #32290

// your answers
type Format<T extends string, R = string, HasSign extends boolean = false> = 
T extends `${infer F}${infer Rest}` 
  ? HasSign extends true 
    ? F extends 's' 
      ? (s: string) => Format<Rest,  R, false> 
      : F extends 'd' 
        ? (d: number) => Format<Rest,  R, false> 
        : Format<Rest, R, false>
    : F extends '%' 
      ? Format<Rest, R, true>
      : Format<Rest, R, false>
  : R

Solution by 437204933 #29571

type Controls = {
  s: [s1: string],
  d: [d1: number]
};

type Format<T extends string, O = string> =
  T extends `${string}%${infer C}${infer Tail}`
  ? C extends keyof Controls
    ? Format<
        Tail,
        O extends (...args: infer Args) => infer Result
        ? (...args: Args) =>
            (...args: Controls[C]) => Result
        : (...args: Controls[C]) => O
      >
    : Format<Tail, O>
  : O;

Solution by AntonPieper #26362

type FormatType = { s: string, d: number, f: number/*, ...*/ };

type Format<T extends string> = T extends `${any}%${infer S}${infer R}` ?
  S extends keyof FormatType ? (arg: FormatType[S]) => Format<R> : Format<R> :
  string;

// old way
// type Format<T extends string> = T extends `${any}%${infer F}${infer R}` ?
//   (F extends `${`d` | `s`}` ?
//     (fill: F extends `d` ? number : string) => Format<R> :
//     Format<R>) :
//   string;

Solution by E-uler #24858

// your answers
type FormatMap = {
  s:string,
  d:number
}

type GetNextChar<C,Last>= Last extends '%' ? '':C

type GetType<C,Last> = Last extends '%'
? C extends keyof FormatMap 
  ? FormatMap[C] 
  :'none'
:'none'  

type GenResult<Arr extends any[],R extends any=string>= Arr extends [infer F,...infer O]  ?  GenResult<O,(a:F)=>R>: R
 


type Format<T extends string,Last extends string='',Result extends any[] = []> = T extends `${infer L}${infer R}`
?  GetType<L,Last> extends infer Type
  ? Type extends 'none'
    ? Format<R,GetNextChar<L,Last>,Result>
    :  Format<R,GetNextChar<L,Last>,[Type,...Result]>
  : GenResult<Result>
: GenResult<Result>

Solution by walker-hzx #24737

type FormatTypes = {
  s: [s1: string];
  d: [d1: number];
}

type Format<T extends string> = T extends `${string}%%${infer TRest extends string}` ? Format<TRest> : (
  T extends `${string}%${infer F extends keyof FormatTypes}${infer TRest extends string}` ? (
    (...args: FormatTypes[F]) => Format<TRest>
  ) : string
)
type T = Format<'a%dbc%s'> // type T = (d1: number) => (s1: string) => string 

Solution by BOCbMOU #23835

interface Dict {
  s: string
  d: number
}

type Format<T extends string> =
T extends `${infer _}%${infer X}${infer R}`
  ? X extends keyof Dict
    ? (x: Dict[X]) => Format<R>
    : Format<R>
  : string

Solution by drylint #22268

type ControlsMap = {
  s: string;
  d: number;
};

type Format<T extends string> = T extends `${string}%${infer C}${infer Rest extends string}` ?
 C extends keyof ControlsMap ? (arg: ControlsMap[C]) => Format<Rest> : Format<Rest>
  : string;

Solution by Karamuto #22001

type ControlsMap = {
  s: string;
  d: number;
};

type Format<T extends string> = T extends `${string}%${infer Control}${infer Rest}`
  ? Control extends keyof ControlsMap
    ? (n: ControlsMap[Control]) => Format<Rest>
    : Format<Rest>
  : string;

type FormatCase1 = Format<'%sabc'>; // FormatCase1 : (n: string) => string
type FormatCase2 = Format<'a%sbc'>; // FormatCase2 : (n: string) => string
type FormatCase3 = Format<'a%dbc'>; // FormatCase3 :  (n: number) => string
type FormatCase4 = Format<'a%%dbc'>; // FormatCase4 :  string
type FormatCase5 = Format<'a%dbc%s'>; // (n: number) => (n: string) => string>
type FormatCase6 = Format<'a%%%dbc'>; // (n: number) => string>

Solution by zqiangxu #21702

type Arguments = {
  '%d': number
  '%s': string
}
type Argument<T extends string> = T extends keyof Arguments ? Arguments[T] : any
type Format<T extends string> = T extends `${string | ''}%${infer Type}${infer Rest}`
  ? `%${Type}` extends keyof Arguments
    ? (a: Argument<`%${Type}`>) => Format<Rest>
    : Format<Rest>
  : string

Solution by milletlovemouse #21595

// your answers
type Format<T extends string> =
  T extends `${ string | '' }%${ infer Type }${ infer Rest }`
    ? Type extends 's'
      ? (s1: string) => Format<Rest>
      : Type extends 'd'
        ? (s1: number) => Format<Rest>
        : Format<Rest>
    : string

Solution by YqxLzx #21063

type Format<T extends string> = 
  T extends `${any}%${infer A}${infer Rest}`
    ? A extends 's'
      ? (a: string) => Format<Rest>
      : A extends 'd'
        ? (a: number) => Format<Rest>
        : A extends '%'
          ? Format<Rest>
          : string
    : string

Solution by zhaoyao91 #20860

// your answers
type Format<T extends string> = T extends `${string | ""}%${infer A}${infer B}`
  ? A extends "s"
    ? (s1: string) => Format<B>
    : A extends "d"
    ? (s1: number) => Format<B>
    : Format<B>
  : string;

Solution by fengjinlong #20243

type Format<T extends string> =
  T extends `${ string | '' }%${ infer Type }${ infer Rest }`
    ? Type extends 's'
      ? (s1: string) => Format<Rest>
      : Type extends 'd'
        ? (s1: number) => Format<Rest>
        : Format<Rest>
    : string

Solution by lvjiaxuan #19522

type MapType = {
  s: string;
  d: number;
};

// εˆ€ζ–­εͺζœ‰ζ˜―ε₯‡ζ•°δΈͺ`%`ζ‰δΌšδΏη•™ζˆε‡½ζ•°γ€‚εΆζ•°δΈͺ`%`εˆ™θ·³θΏ‡ε€„η†ε‰©δ½™ε­—η¬¦δΈ²
type Format<T extends string> =
 T extends `${infer F}%${infer K}${infer R}` 
 ? (K extends keyof MapType ? (arg: MapType[K]) => Format<R> : Format<R>) 
 : string;

Solution by CaoXueLiang #19051

type Descriptors = {
  's': string,
  'd': number,
}
type Format<T extends string> =
  T extends `${infer S}%%${infer E}`
    ? Format<`${S}${E}`>
    : T extends `${string}%${infer D extends keyof Descriptors}${infer E}`
      ? (x: Descriptors[D]) => Format<E>
      : string

Solution by BulatDashiev #16904

interface FormatMap { 's': string; 'd': number; } type Format = T extends ${infer R}${infer E}${infer Q} ? R extends '%' ? E extends 's' | 'd' ? (args: FormatMap[E]) => Format<${Q}> : Format<${E}${Q}> : Format<${E}${Q}> : string;

Solution by my5201314zwl #16499

// your answers
type O = {
  'd': number
  's': string
}
type Format<T extends string, F extends any = string> = 
T extends `${infer J}${infer K}${infer L}` ? J extends '%' ? K extends 'd' | 's' ? Format<L, F extends (args: infer A) => infer R ? (args: A) => (args: O[K]) => R : (args: O[K]) => F>
                                                                                 : K extends '%' ? Format<L, F>
                                                                                                 : Format<`${K}${L}`, F>
                                                           : Format<`${K}${L}`, F>
                                           : F

Solution by Stan-BK #16484

// your answers

type M = {
  d: number;
  s: string;
}

type Format<T extends string, Prev extends string = ''> = T extends `${infer F}${infer R}`
  ? Prev extends '%'
    ? F extends '%'
      ? Format<R, ''>
      : F extends keyof M
        ? (arg: M[F]) => Format<R, ''>
        : Format<R, F>
      : Format<R, F>
  : string

Solution by humandetail #16438

// your answers

type Flags = {
  s: string,
  d: number
}

type FlushEscape<S extends string> = S extends `${infer Pre}%%${infer Post}` ? FlushEscape<`${Pre}${Post}`> : S 

type Format<
  T extends string, 
  E extends string = FlushEscape<T>
> 
= E extends `${string}%${infer Flag extends string}${infer Post}`
? (Flag extends keyof Flags
  ? (argument: Flags[Flag]) => Format<Post> 
  : Format<Post> // Ignoring flags that not exists
  )
: string;


/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Format<'abc'>, string>>,
  Expect<Equal<Format<'a%sbc'>, (s1: string) => string>>,
  Expect<Equal<Format<'a%dbc'>, (d1: number) => string>>,
  Expect<Equal<Format<'a%%dbc'>, string>>,
  Expect<Equal<Format<'a%%%dbc'>, (d1: number) => string>>,
  Expect<Equal<Format<'a%dbc%s'>, (d1: number) => (s1: string) => string>>,
  // These cases works too, I think that throwing type error isn't a great choice
  Expect<Equal<Format<'a%dbco%s%w'>, (d1: number) => (s1: string) => string>>,
  Expect<Equal<Format<'a%dbco%w%s'>, (d1: number) => (s1: string) => string>>,
]

Solution by talkenson #16311

// your answerstype Dictionary =
{
  's' :string,
  'd' :number
} ;

type Trim<
    S extends string > =
    S extends `${infer R}%%${infer U}`
    ? Trim<`${R}${U}`>
    : S ;

type Format<
    T extends string,
    S extends string = Trim<T> > = 
    S extends`${string}%${infer R extends keyof Dictionary}${infer U}`
    ? (arg: Dictionary[R])=>Format<U>
    : string ;

Solution by justBadProgrammer #15862

type Format<T extends string> = buildFn<getStrMarker<T>>;

type buildFn<T, Result extends string | Function = string> = T extends [...infer Rest, infer R]
  ? buildFn<Rest, (s1: 's' extends R ? string : number) => Result>
  : Result

type getStrMarker<T, Result extends any[] = []> = T extends `${string}%${infer U extends 's' | 'd'}${infer Rest}`
  ? getStrMarker<Rest, [...Result, U]>
  : Result;
  1. get all %s %d mark from string
  2. iterate marks array to build return function type.

better solution:

type Format<T extends string> = buildFn<getStrMarker<T>>;

type Marks = {
  s: string;
  d: number;
}

type buildFn<T, Result extends string | Function = string> = T extends [...infer Rest, infer R extends keyof Marks]
  ? buildFn<Rest, (s1: Marks[R]) => Result>
  : Result

type getStrMarker<T, Result extends any[] = []> = T extends `${string}%${infer U extends keyof Marks}${infer Rest}`
  ? getStrMarker<Rest, [...Result, U]>
  : Result;

use marks type to limit match mark.

Solution by ZWkang #15278

// your answers
type PrintMap = {
  s: string;
  d: number;
};

type Format<T extends string> = T extends `${string}%${infer A}${infer B}`
  ? A extends keyof PrintMap
    ? (a: PrintMap[A]) => Format<B>
    : Format<B>
  : string;

Solution by SeptEarlyMorning #11900

type Format<T extends string> =
  T extends `%s${infer Rest}` ? (
    (s1: string) => Format<Rest>
  ) : T extends `%d${infer Rest}` ? (
    (d1: number) => Format<Rest>
  ) : (
    T extends `${string}%${infer Rest}` ? (
      Format<`%${Rest}`>
    ) : (
      string
    )
  )

Playground

Solution by teamchong #11427

// your answers

type Format<T extends string> = T extends `${any}%${infer F extends ('s' | 'd')}${infer E}` ?
  F extends 's' ?
    (s1: string) => Format<`${E}`> :
    (d1: number) => Format<`${E}`> :
  string;

Solution by Joyee691 #11414

type Format<T extends string> = T extends `${infer Start}%${infer F & ('s' | 'd')}${infer End}`
  ? F extends 's'
    ? (s1: string) => Format<`${Start}${End}`>
    : (d1: number) => Format<`${Start}${End}`>
  : string

Solution by aeroxmotion #10544

type SingleFormat<T extends string> = 
  T extends infer I
    ? I extends 's'
      ? string
      : I extends 'd'
        ? number
        : never
    : never

type Format<T extends string> = 
  T extends `${infer I}%${infer J}${infer K}`
    ? (arg: SingleFormat<J>) => Format<`${I}${K}`>
    : string

Solution by DrLee-lihr #10320

type ControlsMap = {
  d: number
  s: string
}

type GetType<T, K extends keyof T> = T[K]

type Format<T extends string> = T extends `${infer S}%${infer C}${infer R}` ? 
                                  C extends keyof ControlsMap ?
                                  (any: GetType<ControlsMap,C>) => Format<R>  : 
                                  Format<R> :
                                  string

Solution by sakthikumaran22 #9613

T extends `${any}%${infer R}`
  ? R extends `${infer L}${infer Rest}`
    ? L extends "s" | "d"
      ? L extends "s"
        ? (s1: string) => Format<Rest>
        : L extends "d"
          ? (d1: number) => Format<Rest>
          : never
      : Format<Rest>
    : R extends "s" | "d"
      ? R extends "s"
        ? (s1: string) => string
        : R extends "d"
          ? (d1: number) => string
          : never
      : string
  : string;

Solution by Psilocine #9021