type-challengesの学習記録
Tuple to Object(初級)
First of Array(初級)
Awaited(初級)
回答
これでは不正解
type MyAwaited<T> = T extends Promise<infer U> ? U : never;
回答
type MyAwaited<T> = T extends PromiseLike<infer U> ? U extends PromiseLike<any> ? MyAwaited<U> : U : never;
Promise
だけなら以下でもOK
type MyAwaited<T> = T extends Promise<infer U> ? U extends Promise<any> ? MyAwaited<U> : U : never;
Concat(初級)
回答
type Concat<T extends readonly any[], U extends readonly any[]> = [...T, ...U];
Includes(初級)
これだと不完全
type Includes<T extends readonly any[], U> = U extends T[number] ? true : false;
回答
完全一致は一癖ある。
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;
Parameters(初級)
回答
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer X) => any ? X : never;
なぜタプル型が返るか?
ChatGPT先生による解説:
関数の引数型は、関数のシグネチャを記述する際に、すべての引数の型を タプル型 としてまとめて表現します
Get Return Type(中級)
回答
type MyReturnType<T> = T extends ((...args: any) => infer X) ? X : never;
Omit(中級)
Readonly 2(中級)
回答
なんか違う。。。
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];
};
回答
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];
};
Deep Readonly(中級)
回答
type DeepReadonly<T> = {
readonly [t in keyof T]: T[t] extends Object ? T[t] extends Function ? T[t] : DeepReadonly<T[t]> : T[t];
};
Chainable Options
回答
チェインを繋げるために自分自身を返す必要がある。
type Chainable<T = {}> = {
option<K extends string, V extends any>(key: K extends keyof T ? never : K, value: V):
Chainable<{
[t in keyof T as t extends K ? never : t]: T[t]
} & {
[k in K]: V
}>
get(): T
}
Last of Array
回答
JSと使い勝手が違うかも。
type Last<T extends any[]> = T extends [...args: any, arg: infer X] ? X : never;
Pop(中級)
回答
先ほどの類題。
type Pop<T extends any[]> = T extends [...args: infer X, arg: any] ? X : [];
Promise.all(中級)
回答途中
declare function PromiseAll<A extends any[]>(values: A): A extends [arg: infer X, ...args: infer Y];
回答
これだと不完全。
declare function PromiseAll<A extends any[]>(values: A): Promise<{
[a in keyof A]: Awaited<A[a]>;
}>;
回答
declare function PromiseAll<A extends any[]>(values: readonly [...A]): Promise<{
[a in keyof A]: Awaited<A[a]>;
}>;
Type Lookup(中級)
回答
type LookUp<U extends Cat | Dog, T extends "cat" | "dog"> = U extends {type: T} ? U : never;
Trim Left(中級)
回答
type TrimLeft<S extends string> = S extends `${' ' | '\n' | '\t'}${infer T}` ? TrimLeft<T> : S;
Trim(中級)
回答
type Trim<S extends string> = S extends `${' ' | '\n' | '\t'}${infer T}`
? Trim<T>
: S extends `${infer T}${' ' | '\n' | '\t'}` ? Trim<T> : S;
Capitalize(中級)
回答
type MyCapitalize<S extends string> = S extends `${infer X}${infer Y}` ? `${Uppercase<X>}${Y}` : '';
Replace(中級)
回答
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;
回答
無駄な処理を省くと以下になる。
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;
ReplaceAll(中級)
回答
type ReplaceAll<S extends string, From extends string, To extends string> =
From extends ''
? S
: S extends `${infer X}${From}${infer Y}`
? `${X}${To}${ReplaceAll<`${Y}`, From, To>}`
: S;
Append Argument(中級)
回答
type AppendArgument<Fn extends Function, A extends any> =
Fn extends (...args: infer X) => infer Y
? (...args: [...X, A]) => Y
: never;
Permutation(中級)
Length of String(中級)
回答
type LengthOfString<S extends string, L = []> =
L extends any[]
? S extends `${S[0]}${infer Y}`
? LengthOfString<Y, [...L, S[0]]>
: L['length']
: never;
Flatten(中級)
回答
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;
回答
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;
Append to object(中級)
回答
type AppendToObject<T extends Object, U extends string, V extends any> = {
[X in keyof T | U]: X extends keyof T ? T[X] : V;
};
Absolute(中級)
回答
BigIntでも対応できるのは面白い!
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer X}` ? X : `${T}`;
String to Union(中級)
回答
特にひねりなし
type StringToUnion<T extends string> = T extends `${infer X}${infer Y}` ? X | StringToUnion<Y> : never;
Merge(中級)
回答
type Merge<F extends Object, S extends Object> = {
[X in keyof (F & S)]: X extends keyof S ? S[X] : X extends keyof F ? F[X] : never;
};
KebabCase(中級)
回答
type KebabCase<S extends string> =
S extends `${infer X}${infer Y}`
? Y extends Uncapitalize<Y>
? `${Uncapitalize<X>}${KebabCase<Y>}`
: `${Uncapitalize<X>}-${KebabCase<Y>}`
: S;
別解
type KebabCase<S extends string> =
S extends `${infer X}${infer Y}`
? Y extends Uncapitalize<Y>
? `${Lowercase<X>}${KebabCase<Y>}`
: `${Lowercase<X>}-${KebabCase<Y>}`
: S;
Diff(中級)
回答
type Diff<O extends Object, O1 extends Object> = {
[o in keyof (O & O1) as o extends keyof O
? o extends keyof O1
? never
: o
: o extends keyof O1
? o
: never
]: o extends keyof O ? O[o] : o extends keyof O1 ? O1[o] : never;
}
AnyOf(中級)
回答
type AnyOf<T extends readonly any[]> =
T extends []
? false
: T extends [infer X, ...args: infer Y]
? X extends (false | null | undefined | 0 | '' | [] | {[key: string]: never})
? AnyOf<Y>
: true
: false;
IsNever (中級)
IsUnion(中級)
ReplaceKeys(中級)
回答
type ReplaceKeys<U, T, Y> = {
[u in keyof U]:
u extends T
? u extends keyof Y
? Y[u]
: never
: U[u];
};
Remove Index Signature(中級)
回答
type RemoveIndexSignature<T> = {
[t in keyof T as string extends t ? never : number extends t ? never : symbol extends t ? never : t]: T[t];
}
Percentage Parser(中級)
回答
愚直に実装
type PercentageParser<A extends string> =
A extends `${infer X}${infer Y}`
? X extends "+" | "-"
? A extends `${X}${infer Y}${"%"}`
? [X, Y, "%"]
: [X, Y, ""]
: A extends `${infer Y}${"%"}`
? ["", Y, "%"]
: ["", A, ""]
: ["", "", ""];
Drop Char(中級)
回答
type DropChar<S extends string, C extends string, T extends string = ""> =
S extends `${infer X}${infer Y}`
? X extends C
? DropChar<Y, C, T>
: DropChar<Y, C, `${T}${X}`>
: T;
MinusOne(中級)
回答
配列の限界?で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,]>;
途中
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;
1001以上の対応は難しいのでパス。
PickByType(中級)
回答
type PickByType<T extends Object, U> = {
[t in keyof T as T[t] extends U ? t : never]: T[t];
}
StartsWith(中級)
回答
type StartsWith<T extends string, U extends string> =
T extends U
? true
: T extends `${infer X extends string}${U}${infer Y extends string}`
? true
: false;
EndsWith(中級)
回答
StartsWithと同じもので可能
type EndsWith<T extends string, U extends string> =
T extends U
? true
: T extends `${infer X extends string}${U}${infer Y extends string}`
? true
: false;
PartialByKeys(中級)
回答
&のままではだめなので、マージする必要がある。
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;
別解
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;
RequiredByKeys(中級)
回答
type RequiredByKeys<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;
OmitByType(中級)
回答
type OmitByType<T extends object, U> = {
[t in keyof T as T[t] extends U ? never : t]: T[t];
}
ObjectEntries(中級)
回答
type ObjectEntries<T extends object> =
Required<T> extends infer X extends T
? {[t in keyof X]: [t, [X[t]] extends [never] ? undefined : X[t]]}[keyof T]
: never;
Shift(中級)
回答
type Shift<T extends any[]> = T extends [arg: infer X, ...args: infer Y] ? [...Y] : [];
Tuple to Nested Object(中級)
回答
type TupleToNestedObject<T extends any[], U> =
T extends [arg: infer X extends string, ...args: infer Y extends any[]]
? {
[x in `${X}`]: Y extends [] ? U : TupleToNestedObject<Y, U>;
}
: U;
Reverse(中級)
回答
type Reverse<T extends any[]> = T extends [...args: infer Y, arg: infer X] ? [X, ...Reverse<Y>] : [];
Flip Arguments(中級)
回答
先ほどのReverseを活用。
type Reverse<T extends any[]> = T extends [...args: infer Y, arg: infer X] ? [X, ...Reverse<Y>] : [];
type FlipArguments<T extends (...args: any) => any> = T extends (...args: infer X extends any[]) => infer Y ? (...args: Reverse<X>) => Y : never;
FlattenDepth(中級)
回答途中
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;
回答
だいぶ無理やり減算処理を実現。
※合っているかは不明(とりあえず今回の問題はクリアした)
※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;
BEM style string(中級)
回答
type BEM<B extends string, E extends string[], M extends string[]> =
E extends [infer X extends string, ...infer Y extends string[]]
? BEM<`${B}__${X}`, [...Y], M>
: M extends [infer X extends string, ...infer Y extends string[]]
? Exclude<`${B}--${X}` | BEM<B, E, [...Y]>, B>
: B;
InorderTraversal(中級)
回答
左の要素は左に、右の要素は右に配置。
type InorderTraversal<T extends TreeNode | null> =
T extends TreeNode
? T["left"] extends TreeNode
? [...InorderTraversal<T["left"]>, T["val"]]
: T["right"] extends TreeNode
? [T["val"], ...InorderTraversal<T["right"]>]
: [T["val"]]
: []
Flip(中級)
回答
type Flip<T extends object> = {
[t in keyof T as T[t] extends (string | number | boolean) ? `${T[t]}` : never]: t;
};
Fibonacci Sequence(中級)
回答
type Fibonacci<T extends number, A extends any[] = [1], B extends any[] = [1], C extends any[] = [1, 1, 1]> =
T extends 1 | 2
? 1
: C["length"] extends T
? [...A, ...B]["length"]
: Fibonacci<T, B, [...A, ...B], [...C, 1]>;
文字の組み合わせ(中級)
回答
type AllCombinations<S extends string, T extends string = ""> =
S extends `${infer X}${infer Y}`
? `${X}${AllCombinations<`${Y}${T}`>}` | `${AllCombinations<`${Y}`, `${T}${X}`>}`
: '';
Greater Than(中級)
回答
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>>
Zip(中級)
回答
type Zip<T extends any[], U extends any[]> =
T extends [infer X, ...infer Y]
? U extends [infer A, ...infer B]
? [[X, A], ...Zip<Y, B>]
: []
: [];
IsTuple(中級)
回答
type IsTuple<T> =
[T] extends [never]
? false
: T extends any[] | readonly any[]
? any[] extends T
? false
: true
: false;
Chunk(中級)
回答
type Chunk<T extends any[], U extends number, R extends any[] = []> =
T extends [infer X, ...infer Y]
? R["length"] extends U
? [[...R], ...Chunk<Y, U, [X]>]
: [...Chunk<Y, U, [...R, X]>]
: [[...R]] extends [[]]
? []
: [[...R]];
Fill(中級)
回答
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]>];
Trim Right(中級)
回答
Trimの類題。
type TrimRight<S extends string> = S extends `${infer T}${" " | "\n" | "\t"}` ? TrimRight<T> : S;
Without(中級)
回答
type Without<T extends number[], U extends number | number[]> =
T extends [infer X, ...infer Y extends number[]]
? U extends number[]
? X extends U[number]
? [...Without<Y, U>]
: [X, ...Without<Y, U>]
: X extends U
? [...Without<Y, U>]
: [X, ...Without<Y, U>]
: [];
Trunc(中級)
回答
type Trunc<T extends string | number> =
`${T}` extends `${infer X}.${infer Y}`
? X extends "-" | ""
? `${X}0`
: X
: `${T}`;
IndexOf(中級)
回答
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;
Join(中級)
回答
type Join<T extends string[], U extends (string | number) = ","> =
T extends [infer X extends string, ...infer Y extends string[]]
? `${X}${U}${Join<Y, U>}` extends `${infer A}`
? A extends `${infer B}${U}`
? B
: A
: never
: "";
LastIndexOf (中級)
回答
だいぶ力技パターン。
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;
Unique(中級)
回答
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]]>];
MapTypes(中級)
回答
type MapTypes<T extends object, R extends { mapFrom: any, mapTo: any }> = {
[t in keyof T]: T[t] extends R["mapFrom"]
? R extends { mapFrom: T[t]}
? R["mapTo"]
: never
: T[t];
};
Construct Tuple(中級)
回答
type ConstructTuple<L extends number, U extends unknown[] = []> =
U["length"] extends L
? U
: ConstructTuple<L, [...U, unknown]>;
Number Range(中級)
回答
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"]]>;
Combination(中級)
回答
他の人の回答を参考にしたが、難しい。
type Combination<T extends string[], U extends string = T[number], K extends string = U> =
K extends U
? K | `${K} ${Combination<T, Exclude<U, K>>}`
: never;
Subsequence (中級)