/**
 * Type the HTTPHeaders object so that it has an `Authentication`
 * property that starts with `Bearer ` and ends with a JWT token.
 *
 * Note: JWT tokens contain 3 parts, separated by dots.
 * More info on https://jwt.io
 * 
 * Hint: You shouldn't need a conditional type.
 */
namespace headers {
  type HTTPHeaders = {
    Authentication: `Bearer ${string}.${string}.${string}`
  };
 
  const test1: HTTPHeaders = {
    // ✅ This is a correct authentication header:
    Authentication:
      "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtIjoiWW91J3JlIGEgbmVyZCA7KSJ9.gfB7ECp1ePeIB4Mh_3Ypci4y7jFjMH9w_BB4rZcMvQM",
  };
 
  const test2: HTTPHeaders = {
    // @ts-expect-error: ❌ Authentication should start with 'Bearer'
    Authentication: "a.b.c",
  };
 
  const test3: HTTPHeaders = {
    // @ts-expect-error: ❌ Authentication should start with 'Bearer'
    Authentication: "oops a.b.c",
  };
 
  const test4: HTTPHeaders = {
    // @ts-expect-error: ❌ token is invalid, only 1 part.
    Authentication: "Bearer abc",
  };
 
  const test5: HTTPHeaders = {
    // @ts-expect-error: ❌ token is invalid, only 2 parts.
    Authentication: "Bearer abc.123",
  };
}
 
/**
 * Implement a `IsYelling` generic that returns
 * true if the input string is in all caps and
 * false otherwise.
 * 
 * You shouldn't need recursion to solve this one.
 */
namespace isYelling {
  type IsYelling<Str extends string> = Str extends Uppercase<Str> ? true : false;
 
  type res1 = IsYelling<"HELLO">;
  type test1 = Expect<Equal<res1, true>>;
 
  type res2 = IsYelling<"Hello">;
  type test2 = Expect<Equal<res2, false>>;
 
  type res3 = IsYelling<"I am Groot">;
  type test3 = Expect<Equal<res3, false>>;
 
  type res4 = IsYelling<"YEAAAH">;
  type test4 = Expect<Equal<res4, true>>;
}
/**
 * Implement a `StartsWith` generic that takes
 * 2 string literals, and returns true if the
 * first string starts with the second one.
 */
namespace startsWith {
  type StartsWith<Str, Start extends string> = Str extends `${Start}${string}`
    ? true
    : false;
 
  type res1 = StartsWith<"getUsers", "get">;
  type test1 = Expect<Equal<res1, true>>;
 
  type res2 = StartsWith<"getArticles", "post">;
  type test2 = Expect<Equal<res2, false>>;
 
  type res3 = StartsWith<"Type-Level Programming!", "Type">;
  type test3 = Expect<Equal<res3, true>>;
}
 

삽질했는디.. 답은 엄청 심플하게 끝나네

/**
 * Write a type-level function that transforms
 * snake_case strings into camelCase.
 */
 
namespace snakeToCamel {
  // 1. _로 나누기
  // 2. 두 번째 원소부터 Capitalize
  // 3. concat
 
  type SplitByUnderscore<
    Str extends string,
    Output extends string[] = [],
  > = Str extends `${infer First}_${infer Rest}`
    ? SplitByUnderscore<Rest, [...Output, First]>
    : [...Output, Str];
 
  type myRes1 = SplitByUnderscore<"a_b_c_d">;
  type myTest1 = Expect<Equal<myRes1, ["a", "b", "c", "d"]>>;
 
  type CapitalizeAll<
    Strings extends string[],
    Output extends string[] = [],
  > = Strings extends [
    infer Head extends string,
    ...infer Rest extends string[],
  ]
    ? CapitalizeAll<Rest, [...Output, Capitalize<Head>]>
    : Output;
 
  type myRes2 = CapitalizeAll<["test", "capitalize", "all"]>;
  type myTest2 = Expect<Equal<myRes2, ["Test", "Capitalize", "All"]>>;
 
  type JoinAll<
    Strings extends string[],
    Output extends string = "",
  > = Strings extends [
    infer Head extends string,
    ...infer Rest extends string[],
  ]
    ? JoinAll<Rest, `${Output}${Head}`>
    : Output;
 
  type myRes3 = JoinAll<["Test", "Capitalize", "All"]>;
  type myTest3 = Expect<Equal<myRes3, "TestCapitalizeAll">>;
 
  type SnakeToCamel<Str extends string> = Uncapitalize<
    JoinAll<CapitalizeAll<SplitByUnderscore<Str>>>
  >;
 
  // it should let strings with no underscore in them unchanged
  type res1 = SnakeToCamel<"hello">;
  type test1 = Expect<Equal<res1, "hello">>;
 
  // one underscore
  type res2 = SnakeToCamel<"hello_world">;
  type test2 = Expect<Equal<res2, "helloWorld">>;
 
  // many underscores
  type res3 = SnakeToCamel<"hello_type_level_type_script">;
  type test3 = Expect<Equal<res3, "helloTypeLevelTypeScript">>;
}
 
/**
 * Re-implement `SpacesToUnderscores` by defining a `Split`
 * and a `Join` generic that behaves like the value-level
 * `.split(separator)` and `.join(separator)` methods.
 */
namespace splitAndJoin {
  type SpacesToUnderscores<Str> = Join<Split<Str, " ">, "_">;
 
  type Split<
    Str,
    Separator extends string,
  > = Str extends `${infer Head}${Separator}${infer Tail}`
    ? [Head, ...Split<Tail, Separator>]
    : [Str];
 
  type Join<List, Separator extends string> = List extends [
    infer Head extends string,
    ...infer Tail extends string[],
  ]
    ? Tail["length"] extends 0
      ? `${Head}`
      : `${Head}${Separator}${Join<Tail, Separator>}`
    : "";
 
  type res1 = Split<"a.b.c", ".">;
  type test1 = Expect<Equal<res1, ["a", "b", "c"]>>;
 
  type res2 = Join<["a", "b", "c"], ".">;
  type test2 = Expect<Equal<res2, "a.b.c">>;
 
  type res3 = SpacesToUnderscores<"hey">;
  type test3 = Expect<Equal<res3, "hey">>;
 
  type res4 = SpacesToUnderscores<"user name">;
  type test4 = Expect<Equal<res4, "user_name">>;
 
  type res5 = SpacesToUnderscores<"type level typescript">;
  type test5 = Expect<Equal<res5, "type_level_typescript">>;
}

보너스 문제는 스킵…