Hard TypeScript Challenges

Push your TypeScript expertise to the limit with these advanced challenges

#6

Simple Vue

A Vue-style defineComponent where this means the right thing in data, computed and methods: three inferred shapes fed back into the same object literal via ThisType.

Hard
#17

Currying 1

Type a currying function that turns a multi-argument function into a chain of single-argument calls. Recursive tuple inference peels one parameter per step.

Hard
#55

Union to Intersection

Turn A | B | C into A & B & C. There is no built-in operator for this; distributive conditionals and contravariant inference get you there.

Hard
#57

Get Required

Write GetRequired<T>, which drops every optional property from an object type. The filter runs inside the mapped type: as-remapping a key to never erases it.

Hard
#59

Get Optional

Build GetOptional<T>, which keeps only the optional fields of an object type. Filtering keys is half the job; each surviving property must also keep its ? modifier.

Hard
#89

Required Keys

Build RequiredKeys<T>, which collects every required key of an object type into a union. Checking for undefined fails; you have to test the ? modifier itself.

Hard
#90

Optional Keys

Build OptionalKeys<T>, which collects every optional key of an object type into a union. The hard part: optionality is a modifier, so checking for undefined gets you nowhere.

Hard
#112

Capitalize Words

Uppercase the first letter of every word in a string type, where a word boundary is any character without an upper or lower case form.

Hard
#114

CamelCase

Convert a snake_case string type to camelCase with recursive template literal inference. The tricky part: characters that cannot be uppercased, like _ and $.

HardPro
#147

C-printf Parser

Parse a C-style printf format string at the type level, collecting placeholders like %d into a tuple. Lazy template inference handles %% escapes for free.

HardPro
#213

Vue Basic Props

Extend Simple Vue with a props option: infer prop types from constructors like Boolean, String or custom classes, including unions from constructor arrays.

HardPro
#223

IsAny

Detect the any type, and only any. Every obvious check produces false positives; the working one-liner is 0 extends 1 & T, and the why behind it is the real lesson.

HardPro
#270

Typed Get

A fully typed version of lodash's get: parse a dot-separated path string with template literal inference and resolve it to the exact value type.

HardPro
#300

String to Number

Convert a string literal type to its number, like Number.parseInt but stricter. One infer extends clause replaces pages of digit-by-digit recursion.

HardPro
#399

Tuple Filter

FilterOut<T, F> removes tuple elements assignable to F. The catch is never, which makes naked conditional checks silently evaporate.

HardPro
#472

Tuple to Enum Object

Convert a string tuple into a readonly enum-like object: PascalCase keys, filtered array keys, and index strings turned back into number literals.

HardPro
#545

printf

Format<T> turns a printf-style format string into a curried function type, one typed argument per placeholder. The twist: the recursion builds function types, not tuples.

HardPro
#553

Deep object to unique

Brand an object and every nested object with its own identity while staying mutually assignable with the original. Nominal typing built by hand.

HardPro
#651

Length of String 2

Count the length of a string type with a tuple accumulator. The naive recursion dies at about 45 characters; tail recursion takes you to 999.

HardPro
#730

Union to Tuple

Convert a union into a tuple even though unions have no order. The key move is extracting a single member via function overload resolution.

HardPro
#847

String Join

A curried join function whose return type is the exact joined string literal, computed from the delimiter and arguments by a recursive template literal type.

HardPro
#956

DeepPick

A Pick that understands dot paths like friend.family.name, building one nested pick per path and folding them into an intersection via contravariant inference.

HardPro
#1290

Pinia

Type Pinia's defineStore: getters are written as functions but read as values, and state is mutable in actions but read-only in getters. ThisType does the work.

HardPro
#1383

Camelize

Rename every snake_case key in an object type to camelCase, recursing through nested objects and tuples. The array branch must come before the object branch.

HardPro
#2059

Drop String

Remove every character of R from the string type S. One recursion turns R into a union of characters, another walks S and filters against it.

HardPro
#2822

Split

A type-level String.split() that turns a string type into a tuple of substrings. Reproducing JavaScript's odd empty-string rules is the hard part.

HardPro
#2828

ClassPublicKeys

Extract the public keys of a class into a union. The answer is one line, because keyof never sees private or protected members in the first place.

HardPro
#2857

IsRequiredKey

IsRequiredKey<T, K> reports whether every key in K is required on T. Optionality is a modifier, not a value type, so the check compares Pick against Required.

HardPro
#2949

ObjectFromEntries

Turn a union of [key, value] tuples into an object type, the type-level Object.fromEntries. One mapped type does it, once you know in can iterate any union.

HardPro
#4037

IsPalindrome

Check whether a string or number reads the same backwards, entirely in types. A recursive template-literal split does the reversal.

HardPro
#5181

Mutable Keys

Build MutableKeys<T>, a union of the non-readonly keys of an object type. Assignability checks ignore readonly, so detecting it takes the Equal trick.

HardPro
#5423

Intersection

The type-level version of Lodash intersection: compute what several lists have in common. Normalize every entry to a union and let & do the set math.

HardPro
#6141

Binary to Decimal

Convert a binary string literal like '1010' into the number type 10. The type system has no arithmetic, so tuples stand in for numbers and spreads do the math.

HardPro
#7258

Object Key Paths

Generate every path string lodash _.get accepts on an object, dot and bracket notation included, by walking the type with recursive template literals.

HardPro
#8804

Two Sum

Solve Two Sum in the type system, where there is no + operator and no loop. Two nested recursions over a tuple, with addition built from tuple lengths.

HardPro
#9155

ValidDate

Implement ValidDate<T>, which checks whether an MMDD string is a real calendar date. Every legal month and day gets enumerated as a union of string literals.

HardPro
#9160

Assign

Recreate Object.assign at the type level: merge an array of sources into a target, later sources winning. Intersections collapse conflicts to never, so they're out.

HardPro
#9384

Maximum

Find the largest number in a tuple type with no greater-than operator in sight. A counting tuple eliminates union members until only the maximum remains.

HardPro
#9775

Capitalize Nest Object Keys

Capitalize every key of an object type recursively, following values into nested arrays. The branch order decides whether tuples survive the mapping.

HardPro
#13580

Replace Union

UnionReplace<T, U> rewrites a union according to a list of [from, to] type pairs: one conditional distributes over the members, another recurses through the pairs.

HardPro
#14080

FizzBuzz

Generate the FizzBuzz sequence as a tuple of string literals, without loops or a modulo operator. Tuple counters and a tail-recursive accumulator do the work.

HardPro
#14188

Run-length encoding

Encode and decode run-length compressed strings at the type level, combining template literal inference, string accumulators, tuple counters and a digit trick.

HardPro
#15260

Tree path array

Path<T> computes every valid key path through a nested object as a union of tuples. The machinery behind type-safe lodash.get and form field paths.

HardPro
#19458

SnakeCase

SnakeCase<T> converts camelCase string types to snake_case by scanning one character at a time. Union inputs work for free thanks to distributive conditionals.

HardPro
#25747

IsNegativeNumber

IsNegativeNumber<N> returns true for negative literals, false for zero and positives, and never for number or unions. Union detection is the tricky part.

HardPro
#28143

OptionalUndefined

Make every property that allows undefined optional, restricted to a chosen key set. Split the object with key remapping, add the ? modifier, merge back.

HardPro
#30178

Unique Items

Write uniqueItems, a function that rejects tuples with duplicate elements and pins the compiler error on each repeated element instead of the whole argument.

HardPro
#30575

BitwiseXOR

XOR two binary string literals of different lengths. Bitwise ops align at the right end, the one end template literal inference cannot reach, so you reverse first.

HardPro
#31797

Sudoku

A type that verifies a solved Sudoku board: 27 region checks built from indexed access on tuples and one union-as-set comparison.

HardPro
#31824

Length of String 3

Count string lengths up to a million characters at the type level. Fixed-width template patterns strip 100,000 characters per match; the counts become digits.

HardPro
#32427

Unbox

Build Unbox<T>, which unwraps functions, promises, arrays and tuples, recursively or to a chosen depth. Fixpoint recursion meets a type-level counter.

HardPro
#32532

Binary Addition

Add two binary numbers, given as bit tuples, by modeling a full adder: a sum and a carry bit per column, carry rippling left. Tuple-length counting tricks are banned.

HardPro
#33763

Union to Object from key

Filter a union of object types down to the members that have a given key. No recursion, no infer: the whole difficulty is understanding distribution.

HardPro
#34286

Take Elements

Take<N, Arr> extracts the first N elements of a tuple, or the last N when N is negative. Accumulator counting and template literal sign detection do the work.

HardPro
#35314

Valid Sudoku

Grade a finished 9x9 Sudoku grid entirely in the type system. Indexed access over unions carves out rows, columns and boxes without any tuple slicing.

HardPro

Ready for the ultimate challenge? Try our extreme challenges or browse all TypeScript challenges!