LoginSignup
7
8

More than 1 year has passed since last update.

[TypeScript] TypeChallengeに挑戦してきました

Posted at

Type Scriptの型システムについて学んでみたいと思ったのでType Challengeに挑戦してきました。(中級まで)
以降は私がType Challengeに挑戦したときに作成した回答です。

easy

// Pick
type MyPick<T, K extends keyof T> = { [key in K]: T[key] };

// Readonly
type MyReadonly<T> = { readonly [key in keyof T]: T[key] };

// TupleToObject
type TupleToObject<T extends readonly string[]> = { [key in T[number]]: key };

// First
type First1<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
type First2<T extends any[]> = T[number] extends never ? never : T[0];

// Length of Tuple
type Length<T extends readonly any[]> = T['length'];

// Exclude
type MyExclude<T, U> = T extends U ? never : T;

// Awaited
type Awaited<T extends Promise<any>> = T extends Promise<infer R> ? R : never;

// If
type If<C extends boolean, T, F> = C extends false ? F : T;

// Concat
type Concat<T extends any[], U extends any[]> = [...T, ...U];

// Includes
type Includes<T extends readonly any[], U> = T extends [infer F, ...infer R] ? ([U, F] extends [F, U] ? true : Includes<R, U>) : false;

// Push
type Push<T extends any[], U> = [...T, U];

// Unshift
type Unshift<T extends any[], U> = [U, ...T];

medium

// Get Return Type
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// Omit
type MyOmit1<T, K> = { [key in keyof T as key extends K ? never : key]: T[key] };
type MyOmit2<T, K> = { [key in Exclude<keyof T, K>]: T[key] };

// Rreadonly 2
type MyReadonly2<T, K extends keyof T = keyof T> = { readonly [key in K]: T[key] } & { [key in Exclude<keyof T, K>]: T[key] };

// DeepReadonly
type DeepReadonly<T> = { readonly [key in keyof T]: T[key] extends { [key: string]: unknown } ? DeepReadonly<T[key]> : T[key] };

// Tuple to Union
type TupleToUnion<T extends readonly any[]> = T[number];

// Chainable Options
type Chainable<T = {}> = {
    option<K extends string, V>(key: K, value: V): Chainable<{ [key in K]: V } & T>;
    get(): T;
};

// Last of Array
type Last<T extends any[]> = T extends [...any[], infer L] ? L : never;

// Pop
type Pop<T extends any[]> = T extends [...infer R, any] ? R : never;

// Promise.all
declare function PromiseAll<T extends any[]>(
    values: readonly [...T]
): Promise<
    {
        [key in keyof T]: T[key] extends Promise<infer L> ? L : T[key];
    }
>;

// Type Lookup
// type LookUp<U extends Animal, T extends U['type']> = T extends 'cat' ? Cat : Dog;
type LookUp<U, T> = U extends { type: T } ? U : never;

// Trim Left
type TrimLeft<S extends string> = S extends `${' ' | '\n' | '\t'}${infer SS}` ? TrimLeft<SS> : S;

// Trim
type TrimRight<S> = S extends `${infer SS}${' ' | '\n' | '\t'}` ? TrimRight<SS> : S;
type Trim1<S extends string> = TrimRight<TrimLeft<S>>;
type Trim2<S extends string> = S extends `${infer L}${' ' | '\n' | '\t'}` | `${' ' | '\n' | '\t'}${infer R}` ? Trim2<R | L> : S;

// Capitalize
type Capitalize2<S extends string> = S extends `${infer F}${infer S}` ? `${Uppercase<F>}${S}` : S;

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

// ReplaceAll
type ReplaceAll<S extends string, From extends string, To extends string> = '' extends From
    ? S
    : S extends `${infer F}${From}${infer R}`
    ? `${F}${To}${ReplaceAll<R, From, To>}`
    : S;

// Append Argument
// https://dev.to/macsikora/advanced-typescript-exercises-question-4-495c
type AppendArgument<Fn extends (...args: any[]) => any, A> = Fn extends (...args: infer T) => infer R ? (...args: [...T, A]) => R : never;

// Permutation
// https://github.com/type-challenges/type-challenges/issues/614
type Permutation<T, K = T> = [T] extends [never] ? [] : K extends K ? [K, ...Permutation<Exclude<T, K>>] : never;

// Length of String
type StringToTuple<S extends string> = S extends `${infer F}${infer R}` ? [F, ...StringToTuple<R>] : [];
type LengthOfString<S extends string> = StringToTuple<S>['length'];

// Flatten
type Flatten<T extends any[]> = T extends [infer F, ...infer R]
    ? F extends any[]
        ? [...Flatten<F>, ...Flatten<R>]
        : [F, ...Flatten<R>]
    : [];

// ...never を含むタプル型の計算結果はneverになる
type B = [1, 2, 3, ...never];

// Append to Object
type AppendToObject<T, U extends string, V> = { [key in U | keyof T]: key extends keyof T ? T[key] : V };

// Absolute
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer R}` ? R : `${T}`;

// String to Union
type StringToUnion<T extends string> = T extends `${infer F}${infer R}` ? F | StringToUnion<R> : never;

// Merge
type Merge<F, S> = {
    [key in keyof F | keyof S]: key extends keyof S ? S[key] : key extends keyof F ? F[key] : never;
};

// Camel Case
type CamelCase<S extends string> = S extends `${infer F1}${infer F2}${infer R}`
    ? F1 extends '-'
        ? F2 extends '-'
            ? `${F1}${CamelCase<`${F2}${R}`>}`
            : F2 extends Uppercase<F2>
            ? `${F1}${Uppercase<F2>}${CamelCase<R>}`
            : `${Uppercase<F2>}${CamelCase<R>}`
        : `${F1}${CamelCase<`${F2}${R}`>}`
    : S;

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

type KebabCase<S extends string> = S extends `${infer F1}${infer F2}${infer R}`
    ? F2 extends Alpha
        ? F2 extends Uppercase<F2>
            ? `${Lowercase<F1>}-${KebabCase<`${F2}${R}`>}`
            : `${Lowercase<F1>}${KebabCase<`${F2}${R}`>}`
        : `${Lowercase<F1>}${KebabCase<`${F2}${R}`>}`
    : Lowercase<S>;

// Diff
type Diff<O, O1> = {
    [key in Exclude<keyof O, keyof O1> | Exclude<keyof O1, keyof O>]: key extends keyof O ? O[key] : key extends keyof O1 ? O1[key] : never;
};

// AnyOf
type AnyOf<T extends readonly any[]> = T extends [infer F, ...infer R]
    ? F extends 0 | '' | false
        ? AnyOf<R>
        : [] extends F
        ? AnyOf<R>
        : keyof F extends never
        ? AnyOf<R>
        : true
    : false;

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

// IsUnion
type IsUnion1<T, U = T> = T[] extends never[] ? false : T extends T ? (Exclude<U, T>[] extends never[] ? false : true) : never;

type IsUnion2<T, U = T> = T extends T ? (U | T extends U & T ? false : true) : never;

type IsUnion3<T> = (<D>() => D extends [T] ? 1 : 2) extends <D>() => D extends (T extends T ? [T] : never) ? 1 : 2 ? false : true;

// ReplaceKeys
type ReplaceKeys<U, T extends string, Y extends {}> = U extends U
    ? {
          [key in keyof U]: key extends T ? (key extends keyof Y ? Y[key] : never) : U[key];
      }
    : never;

// RemoveIndexSignature
type RemoveIndexSignature<T> = {
    [key in keyof T as string extends key ? never : number extends key ? never : key]: T[key];
};

// PercentageParser
type PercentageParser<A extends string> = A extends `${infer S}${infer R}`
    ? S extends '+' | '-'
        ? R extends `${infer N}%`
            ? [S, N, '%']
            : [S, R, '']
        : A extends `${infer V}%`
        ? ['', V, '%']
        : ['', A, '']
    : ['', '', ''];

// DropChar
type DropChar<S, C extends string> = S extends `${infer F}${C}${infer R}` ? `${F}${DropChar<R, C>}` : S;

// MinusOne
type T10<T extends any[]> = [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T];
type DigitToArray<T extends string, R extends any[] = []> = `${R['length']}` extends T ? R : DigitToArray<T, [1, ...R]>;
type StringToArray<T extends string, R extends any[] = []> = T extends `${infer F}${infer E}`
    ? StringToArray<E, [...T10<R>, ...DigitToArray<F>]>
    : R;
type MinusOne<T extends number> = StringToArray<`${T}`> extends [any, ...infer R] ? R['length'] : 0;

// PickByType
type PickByType<T, U> = {
    [key in keyof T as T[key] extends U ? key : never]: T[key];
};

// StartsWith
type StartsWith<T extends string, U extends string> = T extends `${U}${infer R}` ? true : false;

// EndsWith
type EndsWith<T extends string, U extends string> = T extends `${infer R}${U}` ? true : false;

// PartialByKeys
type PartialByKeys<T, K = keyof T> = {
    [key in keyof T as key extends K ? never : key]: T[key];
} &
    {
        [key in keyof T as key extends K ? key : never]?: key extends keyof T ? T[key] : never;
    } extends infer I
    ? {
          [key in keyof I]: I[key];
      }
    : never;

// RequiredByKeys
type RequiredByKeys<T, K = keyof T> = {
    [key in keyof T as key extends K ? never : key]: T[key];
} &
    {
        [key in keyof T as key extends K ? key : never]-?: T[key];
    } extends infer I
    ? {
          [key in keyof I]: I[key];
      }
    : never;

// Mutable
type Mutable<T> = {
    -readonly [key in keyof T]: T[key];
};

// OmitByType
type OmitByType<T, U> = {
    [key in keyof T as T[key] extends U ? never : key]: T[key];
};

// ObjectEntries
type ObjectEntries<T> = {
    [key in keyof T]-?: [key, T[key] extends infer F | undefined ? F : T[key]];
}[keyof T];

// Shift
type Shift<T extends any[]> = T extends [any, ...infer R] ? R : [];

// TupleToNestedObject
type TupleToNestedObject<T extends any[], U> = T extends [infer F, ...infer R] ? { [key in F & string]: TupleToNestedObject<R, U> } : U;

// Reverse
type Reverse<T extends any[]> = T extends [infer F, ...infer R] ? [...Reverse<R>, F] : [];

// FlipArguments
type FlipArguments<T> = T extends (...args: infer A) => infer R ? (...args: Reverse<A>) => R : never;

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8