Open186

type-challengesの学習記録

YaonaYaona
YaonaYaona

回答
これでは不正解

type MyAwaited<T> = T extends Promise<infer U> ? U : never;
YaonaYaona

回答

type MyAwaited<T> = T extends PromiseLike<infer U> ? U extends PromiseLike<any> ? MyAwaited<U> : U : never;
YaonaYaona

Promiseだけなら以下でもOK

type MyAwaited<T> = T extends Promise<infer U> ? U extends Promise<any> ? MyAwaited<U> : U : never;
YaonaYaona
YaonaYaona

これだと不完全

type Includes<T extends readonly any[], U> = U extends T[number] ? true : false;
YaonaYaona

回答
完全一致は一癖ある。

type MyEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
type Includes<T extends readonly any[], U> = T extends [infer X, ...infer Y] 
  ? MyEqual<U, X> extends true
    ? true
    : Includes<Y, U>
  : false;
YaonaYaona
YaonaYaona

回答
なんか違う。。。

type MyReadonly2<T, K = keyof T> = {
  [t in keyof T as t extends K ? never : t]: T[t]; 
} & {
  readonly [t in keyof T as t extends K ? t : never]: T[t]; 
};

YaonaYaona

回答
Kの指定方法の違い。

type MyReadonly2<T, K extends keyof T = keyof T> = {
  [t in keyof T as t extends K ? never : t]: T[t]; 
} & {
  readonly [t in keyof T as t extends K ? t : never]: T[t]; 
};

YaonaYaona
YaonaYaona

回答途中

declare function PromiseAll<A extends any[]>(values: A): A extends [arg: infer X, ...args: infer Y];
YaonaYaona

回答
これだと不完全。

declare function PromiseAll<A extends any[]>(values: A): Promise<{
  [a in keyof A]: Awaited<A[a]>;
}>;
YaonaYaona

回答

declare function PromiseAll<A extends any[]>(values: readonly [...A]): Promise<{
  [a in keyof A]: Awaited<A[a]>;
}>;
YaonaYaona
YaonaYaona

回答

type Replace<S extends string, From extends string, To extends string> = 
  From extends ''
  ? S
  : S extends `${From}${infer Y}`
    ? `${To}${Y}`
    : S extends `${infer X}${From}${infer Y}`
      ? `${X}${To}${Y}`
      : S extends `${infer X}${From}`
        ? `${X}${To}`
        : S;
YaonaYaona

回答
無駄な処理を省くと以下になる。

type Replace<S extends string, From extends string, To extends string> = 
  From extends ''
  ? S
  : S extends `${infer X}${From}${infer Y}`
    ? `${X}${To}${Y}`
    : S;
YaonaYaona
YaonaYaona

回答

type Flatten<S extends any[], T = []> = 
  T extends any[]
    ? S extends [S[0], ...args: infer X] 
      ? S[0] extends any[]
        ? Flatten<[...S[0], ...X], T>
        : Flatten<X, [...T, S[0]]>
      : T
    : never;
YaonaYaona

回答

type Flatten<S extends any[], T extends any[] = []> = 
  S extends [S[0], ...args: infer X] 
    ? S[0] extends any[]
      ? Flatten<[...S[0], ...X], T>
      : Flatten<X, [...T, S[0]]>
    : T;
YaonaYaona
YaonaYaona

回答

type KebabCase<S extends string> = 
  S extends `${infer X}${infer Y}`
    ? Y extends Uncapitalize<Y>
      ? `${Uncapitalize<X>}${KebabCase<Y>}`
      : `${Uncapitalize<X>}-${KebabCase<Y>}`
    : S;
YaonaYaona

別解

type KebabCase<S extends string> = 
  S extends `${infer X}${infer Y}`
    ? Y extends Uncapitalize<Y>
      ? `${Lowercase<X>}${KebabCase<Y>}`
      : `${Lowercase<X>}-${KebabCase<Y>}`
    : S;
YaonaYaona
YaonaYaona

回答

type IsNever<T extends any> = 
  [T] extends [never]
  ? true
  : false;
YaonaYaona

参考

そもそもの原因は、「neverは空のunionであるがdistributiveに解決しようとして、結果適用されない」ということでした。 conditional typeをdistributiveに適用しない方法が公式でも紹介されており、 [] で囲めばOKとのことなので上記のコードで解決できました。

https://www.m3tech.blog/entry/2023/03/10/142235

YaonaYaona
YaonaYaona

回答

type IsUnion<T, S = T> =
  [T] extends [never]
    ? false
    : T extends S
      ? [S] extends [T]
        ? false
        : true
      : false;
YaonaYaona
YaonaYaona

回答
配列の限界?で1000までしか不可。

type MinusOne<T extends number, C extends any[] = [1]> = 
  T extends C["length"]
    ? C extends [infer X, ...args: infer Y]
      ? [...Y]["length"]
      : C["length"]
    : MinusOne<T, [1, ...C,]>;
YaonaYaona

途中

type MinusOne<T extends number, C extends any[] = []> = 
  `${T}` extends `${infer X extends number}${infer Y extends number}`
    ? MinusOne<Y, [...C, X]>
    : C extends [...args: infer X extends number[], arg: infer Y extends number]
      ? Y extends 0
        ? MyMinusOne<Y>
        : `${Flat<X>}${MyMinusOne<Y>}` extends infer Z extends number
          ? Z
          : never
      : never;
YaonaYaona
YaonaYaona

回答
&のままではだめなので、マージする必要がある。

type PartialByKeys<T extends Object, K extends keyof T = keyof T> = {
  [t in keyof T as t extends K ? never : t]: T[t];
} & {
  [k in K]?: T[k];
} extends infer X ? {[x in keyof X]: X[x]} : never;
YaonaYaona

別解

type PartialByKeys<T extends Object, K extends keyof T = keyof T> = {
  [t in keyof Omit<T, K>]: T[t];
} & {
  [k in K]?: T[k];
} extends infer X ? {[x in keyof X]: X[x]} : never;
YaonaYaona
YaonaYaona

回答途中

type FlattenOne<S extends any[]> = 
  S extends [S[0], ...args: infer X] 
    ? S[0] extends any[]
      ? [...S[0], ...X]
      : [S[0], ...FlattenOne<[...X]>]
    : S;

type MinusOne<T extends string> =
  T extends `${infer X extends number}${infer Y extends string}`
    ? Y extends ""
      ? ["9", "0", "1", "2", "3", "4", "5", "6", "7", "8"][X]
      : Y extends "0"
        ? `${MinusOne<`${X}`>}${MinusOne<Y>}`
        : `${X}${MinusOne<Y>}`
    : never;

type FlattenDepth<T extends any[], U extends number = 1> = 
  U extends 1
  ? FlattenOne<T>
  : T extends FlattenOne<T>
      ? T
      : MinusOne<`${U}`> extends `${infer X extends number}`
        ? FlattenDepth<FlattenOne<T>, X>
        : never;

YaonaYaona

回答
だいぶ無理やり減算処理を実現。
※合っているかは不明(とりあえず今回の問題はクリアした)
※110->9になるため、MinusOneは間違っている

type FlattenOne<S extends any[]> = 
  S extends [S[0], ...args: infer X] 
    ? S[0] extends any[]
      ? [...S[0], ...FlattenOne<[...X]>]
      : [S[0], ...FlattenOne<[...X]>]
    : S;

type MinusOne<T extends string> =
  T extends `${infer X extends number}${infer Y extends string}`
    ? Y extends ""
      ? ["9", "0", "1", "2", "3", "4", "5", "6", "7", "8"][X]
      : Y extends "0"
        ? `${MinusOne<`${X}`>}${MinusOne<Y>}` extends `0${infer A}`
          ? `${A}`
          : `${MinusOne<`${X}`>}9`
        : `${X}${MinusOne<Y>}` extends `${X}9${infer Z}`
          ? `${Y}` extends `9${infer A}`
            ? `${X}9${Z}`
            : `${MinusOne<`${X}`>}9${Z}` extends `0${infer A}`
              ? `${A}`
              : `${MinusOne<`${X}`>}9${Z}`
          : `${X}${MinusOne<Y>}`
    : never;

type FlattenDepth<T extends any[], U extends number = 1> = 
  U extends 1
  ? FlattenOne<T>
  : T extends FlattenOne<T>
      ? T
      : MinusOne<`${U}`> extends `${infer X extends number}`
        ? FlattenDepth<FlattenOne<T>, X>
        : never;
YaonaYaona
YaonaYaona

回答
Union型を作成し、上の桁から比較。
不一致または桁数が異なる時に最終判定。

type Split<T extends (string | number)> = 
  `${T}` extends `${infer X extends number}${infer Y extends string}`
    ? [X, ...Split<Y>]
    : [];

type GetUnion<T extends number, U extends any[] = []> = 
  T extends U["length"]
    ? [U["length"], ...U][number]
    : GetUnion<T, [...U, U["length"]]>;

type GreaterThanAll<T extends number[], U extends number[]> =
  GetUnion<T["length"]> extends GetUnion<U["length"]>
    ? GetUnion<U["length"]> extends GetUnion<T["length"]>
      ? T extends [infer X extends number, ...infer Y extends number[]]
        ? U extends [infer A extends number, ...infer B extends number[]]
          ? GetUnion<X> extends GetUnion<A>
            ? GetUnion<A> extends GetUnion<X>
              ? GreaterThanAll<Y, B>
              : false
            : true
          : true
        : false
      : false
    : true;
    
type GreaterThan<T extends number, U extends number> = GreaterThanAll<Split<T>, Split<U>>
YaonaYaona
YaonaYaona

回答
Lの値で分岐。

type Fill<
  T extends unknown[],
  N,
  Start extends number = 0,
  End extends number = T['length'],
  L extends number[] = [],
> =
  T[L["length"]] extends undefined
    ? []
    : L["length"] extends Start
        ? L["length"] extends End
          ? [T[L["length"]], ...Fill<T, N, Start, End, [1, ...L]>]
          : [N, ...Fill<T, N, Start, End, [2, ...L]>]
        : L extends [infer X extends number, ...infer Y]
          ? X extends 2
            ? L["length"] extends End
              ? [T[L["length"]], ...Fill<T, N, Start, End, [1, ...L]>]
              : [N, ...Fill<T, N, Start, End, [2, ...L]>]
            : [T[L["length"]], ...Fill<T, N, Start, End, [1, ...L]>]
          : [T[L["length"]], ...Fill<T, N, Start, End, [1, ...L]>];
YaonaYaona
YaonaYaona

回答
anyの判定はkeyof

type IndexOf<T extends any[], U extends any, L extends number[] = []> =
  T extends [infer X, ...infer Y]
    ? X extends U
      ? U extends X
        ? keyof X extends keyof U
          ? keyof U extends keyof X
            ? L["length"]
            : IndexOf<Y, U, [...L, 1]>
          : IndexOf<Y, U, [...L, 1]>
        : IndexOf<Y, U, [...L, 1]>
      : IndexOf<Y, U, [...L, 1]>
    : -1;
YaonaYaona
YaonaYaona

回答
だいぶ力技パターン。

type IndexOf<T extends any[], U extends any, L extends number[] = []> =
  T extends [infer X, ...infer Y]
    ? X extends U
      ? U extends X
        ? keyof X extends keyof U
          ? keyof U extends keyof X
            ? L["length"]
            : IndexOf<Y, U, [...L, 1]>
          : IndexOf<Y, U, [...L, 1]>
        : IndexOf<Y, U, [...L, 1]>
      : IndexOf<Y, U, [...L, 1]>
    : -1;

type Reverse<T extends any[]> = T extends [...args: infer Y, arg: infer X] ? [X, ...Reverse<Y>] : [];

type Pop<T extends any[], U extends number, L extends number[] = []> =
  U extends L["length"]
    ? T
    : T extends [...infer X, infer Y]
      ? Pop<X, U, [1, ...L]>
      : [];

type LastIndexOf<T extends any[], U extends any> =
  IndexOf<Reverse<T>, U> extends infer X extends number
    ? X extends -1
      ? -1
      : Pop<Pop<T, X>, 1>["length"]
    : never;
YaonaYaona
YaonaYaona

回答
IndexOfにnever判定を追加して実施。

type IndexOf<T extends any[], U extends any, L extends number[] = []> =
  T extends [infer X, ...infer Y]
    ? [X] extends [U]
      ? [U] extends [X]
        ? keyof X extends keyof U
          ? keyof U extends keyof X
            ? L["length"]
            : IndexOf<Y, U, [...L, 1]>
          : IndexOf<Y, U, [...L, 1]>
        : IndexOf<Y, U, [...L, 1]>
      : IndexOf<Y, U, [...L, 1]>
    : -1;

type Unique<T extends any[], L extends any[] = []> = 
  T["length"] extends 0
    ? L
    : T extends [T[0], ...infer X]
      ? IndexOf<L, T[0]> extends -1
        ? [...Unique<X, [...L, T[0]]>]
        : [...Unique<X, L>]
      : [...Unique<[], [...L, T[0]]>];
YaonaYaona
YaonaYaona

回答

type NumberRange<L extends number, H extends number, T extends number[] = [], U extends number[] = []> = 
  U["length"] extends 0
    ? T["length"] extends L
      ? NumberRange<L, H, [1, ...T], [...U, L]>
      : NumberRange<L, H, [1, ...T], U>
    : T["length"] extends H
      ? [...U, T["length"]][number]
      : NumberRange<L, H, [1, ...T], [...U, T["length"]]>;