Skip to content

Type Challenges

Easy 13

🔍 Pick
TypeScript
type MyPick<T, K extends keyof T> = Omit<T, Exclude<keyof T, K>>;

type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
🔍 Readonly
TypeScript
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};
🔍 Tuple to Object
TypeScript
type TupleToObject<T extends readonly PropertyKey[]> = {
  [K in T[number]]: K;
};
🔍 First of Array
TypeScript
type First<T extends readonly unknown[]> = T extends [infer F, ...unknown[]]
  ? F
  : never;
🔍 Length of Tuple
TypeScript
type Length<T extends readonly unknown[]> = T["length"];
🔍 Exclude
TypeScript
type MyExclude<T, U> = T extends U ? never : T;
🔍 Awaited
TypeScript
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U>
  ? U extends PromiseLike<any>
    ? MyAwaited<U>
    : U
  : never;
🔍 If
TypeScript
type If<C extends boolean, T, F> = C extends true ? T : F;
🔍 Concat
TypeScript
type Concat<T extends readonly unknown[], U extends readonly unknown[]> = [
  ...T,
  ...U
];
🔍 Includes
TypeScript
type Includes<T extends readonly unknown[], U> = T extends [
  infer First,
  ...infer Rest
]
  ? Equal<First, U> extends true
    ? true
    : Includes<Rest, U>
  : false;
🔍 Push
TypeScript
type Push<T extends unknown[], U> = [...T, U];
🔍 Unshift
TypeScript
type Unshift<T extends unknown[], U> = [U, ...T];
🔍 Parameters
TypeScript
type MyParameters<T extends (...args: readonly any[]) => unknown> = T extends (
  ...args: infer R
) => unknown
  ? [...R]
  : never;

Medium 102

🔍 Get Return Type
TypeScript
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
🔍 Omit
TypeScript
type MyOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

type MyOmit<T, K extends keyof T> = {
  [P in keyof T as P extends K ? never : P]: T[P];
};
🔍 Readonly 2
TypeScript
type MyReadonly2<T, K extends keyof T = keyof T> = Omit<T, K> & {
  readonly [P in K]: T[P];
};
🔍 Deep Readonly
TypeScript
type DeepReadonly<T> = {
  readonly [K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>;
};
🔍 Tuple to Union
TypeScript
type TupleToUnion<T extends unknown[]> = T[number];
🔍 Chainable Options
TypeScript
type Chainable<T = {}> = {
  option: <K extends string, V>(
    key: K extends keyof T ? never : K,
    value: V
  ) => Chainable<Omit<T, K> & Record<K, V>>;
  get: () => T;
};
🔍 Last of Array
TypeScript
type Last<T extends readonly unknown[]> = T extends [...infer _, infer Last]
  ? Last
  : never;
🔍 Pop
TypeScript
type Pop<T extends unknown[]> = T extends []
  ? []
  : T extends [...infer Before, infer _]
  ? Before
  : never;
🔍 Promise.all
TypeScript
declare function PromiseAll<T extends unknown[]>(
  values: readonly [...T]
): Promise<{
  [K in keyof T]: Awaited<T[K]>;
}>;
🔍 Type Lookup
TypeScript
type LookUp<U, T extends string> = U extends { type: T } ? U : never;
🔍 TrimLeft
TypeScript
type Space = " " | "\n" | "\t";
type TrimLeft<S extends string> = S extends `${Space}${infer R}`
  ? TrimLeft<R>
  : S;
🔍 Trim
TypeScript
type Space = " " | "\n" | "\t";
type Trim<S extends string> = S extends
  | `${Space}${infer R}`
  | `${infer R}${Space}`
  ? Trim<R>
  : S;
🔍 Capitalize
TypeScript
type MyCapitalize<S extends string> = S extends `${infer head}${infer tail}`
  ? `${Uppercase<head>}${tail}`
  : S;
🔍 Replace
TypeScript
type Replace<
  S extends string,
  From extends string,
  To extends string
> = From extends ""
  ? S
  : S extends `${infer A}${From}${infer B}`
  ? `${A}${To}${B}`
  : S;
🔍 ReplaceAll
TypeScript
type ReplaceAll<
  S extends string,
  From extends string,
  To extends string
> = From extends ""
  ? S
  : S extends `${infer A}${From}${infer B}`
  ? `${A}${To}${ReplaceAll<B, From, To>}`
  : S;
🔍 Append Argument
TypeScript
type AppendArgument<Fn extends (...args: any[]) => any, A> = Fn extends (
  ...args: infer P
) => infer R
  ? (...args: [...P, A]) => R
  : never;
🔍 Permutation
TypeScript
type Permutation<T, K = T> = [T] extends [never]
  ? []
  : K extends T
  ? [K, ...Permutation<Exclude<T, K>>]
  : never;
🔍 Length of String
TypeScript
type StringToArray<S extends string> = S extends `${infer A}${infer B}`
  ? [A, ...StringToArray<B>]
  : [];
type LengthOfString<S extends string> = StringToArray<S>["length"];
🔍 Flatten
TypeScript
type Flatten<S extends any[]> = S extends [infer First, ...infer Rest]
  ? First extends any[]
    ? [...Flatten<First>, ...Flatten<Rest>]
    : [First, ...Flatten<Rest>]
  : [];
🔍 Append To Object
TypeScript
// ❌ 交叉类型不自动展开计算 KV
type AppendToObject<T, U extends string, V> = {
  [K in U]: V;
} & T;

// ✅ 强制重建对象
type AppendToObject<T, U extends string, V> = Omit<T & { [key in U]: V }, never>

// ✅ 手动创建新对象
type AppendToObject<T, U extends string, V> = {
  [K in keyof T | U]: K extends keyof T ? T[K] : V;
};