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;
};