Closed23

💻 Type challenge / Medium (2 of 10) やっていくスレ

snakasnaka

Pop

これも Last とかやってたら簡単

type Pop<T extends any[]> = T extends [...(infer Left), infer _] ? Left : never
snakasnaka

別解みたところ infer _ の箇所は any とか unknown にしても良さそう

snakasnaka

Promise.all

むずいな...

const promiseAllTest1 = PromiseAll([1, 2, 3] as const)
// => PromiseAll([1, 2, 3] as const): Promise<[1, 2, 3]>

以下は愚直に書いた例だけど、この結果を柔軟に取り出すにはどうするんだっけ?

declare function PromiseAll<T extends readonly unknown[]>(values: T): Promise<[T[0], T[1], T[2]]>
snakasnaka

T の型制約を Tuple として書くとよさそう

declare function PromiseAll<T extends readonly [...any]>(values: T): Promise<T>
snakasnaka

以下で readonly はずせた
これで1つのテストケースはクリアできたが、あと2つ

declare function PromiseAll<T extends readonly [...any]>(values: T):
  T extends readonly [...any: infer U]
    ? Promise<U>
    : Promise<T>
snakasnaka

他の人の回答見てる

Dowanna さん回答 - type-challenges-judge

// T extends readonly unknown[]だとreadonly配列が返却されるため[...T]が必要
declare function PromiseAll<T extends unknown[]>(args: readonly [...T]): Promise<{
  [P in keyof T]: T[P] extends Promise<infer S> ? S : T[P]
}>

配列も X in keyof Y 使えるのか、 Object っぽい型だけだと思いこんでいた

snakasnaka

関数に readonly の値を渡すためには引数の定義の箇所でも明示的に readonly とする必要があったのか
そのあたりの理解があいまいだった

type Resolved<T extends readonly [...any]> = {
  [K in keyof T]: T[K] extends Promise<infer U> ? U : T[K]
}
declare function PromiseAll<T extends [...any]>(values: readonly [...T]): Promise<Resolved<T>>
snakasnaka

Playground のテストは通ったけど Judge が通らなかった

snakasnaka

通っているやつと見比べる

( ACCEPT になっているやつ)

declare function PromiseAll<T extends unknown[]>(args: readonly [...T]): Promise<{
  [P in keyof T]: T[P] extends Promise<infer S> ? S : T[P]
}>
snakasnaka

ほとんど変わらないと思うけど、以下でもダメだな...

declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{
  [K in keyof T]: T[K] extends Promise<infer U> ? U : T[K]
}>
snakasnaka

ACCEPT になっているはずの回答をそのまま提出しても WRONG ANSWER になってしまうのでジャッジが間違っている可能性がある

snakasnaka

Type Lookup

むずかしく考えて解けなかった。

type LookUp<U, T> = U extends { type: T } ? U : never

Discriminated Union の考え方を型に適用できるはず、という発想はあったが U['type'] extends T のように判定を行っていたのがダメだった

(ダメだった例)

type LookUp<U extends { type: string }, T> = U['type'] extends T ? U : never
snakasnaka

Trim Left

template literal で infer が使えたというのを思い出せた時点で勝てた

type TrimLeft<S extends string> =
  S extends ` ${infer T}` | `\n${infer T}` | `\t${infer T}`
    ? TrimLeft<T>
    : S
snakasnaka

他の人の例を見て、もうちょっとシンプルにできた

type TrimLeft<S extends string> =
  S extends `${ ' ' | '\n' | '\t' }${infer T}`
    ? TrimLeft<T>
    : S
snakasnaka

Trim

素直にやるとこうなるが、これでよいのかな?

type Space = ` ` | '\n' | `\t`
type Trim<S extends string> =
  S extends `${Space}${infer T}` | `${infer T}${Space}`
    ? Trim<T>
    : S
snakasnaka

Capitalize

Capitalize そのまま使う... のか?

type MyCapitalize<S extends string> = Capitalize<S>

なんか違う気がする....

snakasnaka

infer で文字列を First / Rest に分割できることを知ったので
愚直にやってみた

type MyUpper<S extends string> =
  S extends 'a' ? 'A'
  : S extends 'b' ? 'B'
  : S extends 'c' ? 'C'
  : S extends 'd' ? 'D'
  : S extends 'e' ? 'E'
  : S extends 'f' ? 'F'
  : S extends 'g' ? 'G'
  : S extends 'h' ? 'H'
  : S extends 'i' ? 'I'
  : S extends 'j' ? 'J'
  : S extends 'k' ? 'K'
  : S extends 'l' ? 'L'
  : S extends 'm' ? 'M'
  : S extends 'n' ? 'N'
  : S extends 'o' ? 'O'
  : S extends 'p' ? 'P'
  : S extends 'q' ? 'Q'
  : S extends 'r' ? 'R'
  : S extends 's' ? 'S'
  : S extends 't' ? 'T'
  : S extends 'u' ? 'U'
  : S extends 'v' ? 'V'
  : S extends 'w' ? 'W'
  : S extends 'x' ? 'X'
  : S extends 'y' ? 'Y'
  : S extends 'z' ? 'Z'
  : S

type MyCapitalize<S extends string> =
  S extends `${infer First}${infer Rest}`
    ? `${MyUpper<First>}${Rest}`
    : ''
snakasnaka

mapping バージョン

type LtoU = {
  'a': 'A'
  'b': 'B'
  'c': 'C'
  'd': 'D'
  'e': 'E'
  'f': 'F'
  'g': 'G'
  'h': 'H'
  'i': 'I'
  'j': 'J'
  'k': 'K'
  'l': 'L'
  'm': 'M'
  'n': 'N'
  'o': 'O'
  'p': 'P'
  'q': 'Q'
  'r': 'R'
  's': 'S'
  't': 'T'
  'u': 'U'
  'v': 'V'
  'w': 'W'
  'x': 'X'
  'y': 'Y'
  'z': 'Z'
}

type MyCapitalize<S extends string> =
  S extends `${infer F}${infer R}`
    ? F extends keyof LtoU
      ? `${LtoU[F]}${R}`
      : `${F}${R}`
    : ''
snakasnaka

Replace

type Replace<S extends string, From extends string, To extends string> = 
  From extends ''
    ? S
    : S extends `${infer L}${From}${infer R}`
      ? `${L}${To}${R}`
      : S

From が '' の場合は S をそのまま
それ意外は From にマッチした部分を To に置き換え
From の前後に infer L / R 入れて To を組み立てるのがポイント

snakasnaka

ここまでの進捗

Promise.all がなぜか Accept にならないのが残ってる

このスクラップは2023/12/09にクローズされました