#4037β€’Hard

IsPalindrome

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

IsPalindrome<121> asks the compiler to reverse a number's digits, so first you teach it to reverse a string.

The task: check whether a string or number reads the same forwards and backwards. Along the way you'll pick up two techniques you'll reuse constantly: recursively reversing a string at the type level, and using template literals to treat numbers and strings uniformly, the same trick that powers type-safe route parsers and key transformers.

For example:

IsPalindrome<'abc'> // false
IsPalindrome<121> // true

Challenge Instructions: IsPalindrome

Hard

Implement type IsPalindrome<T> to check whether a string or number is palindrome.

For example:

IsPalindrome<'abc'> // false
IsPalindrome<121> // true

View on GitHub: https://tsch.js.org/4037

Change the following code to make the test cases pass (no type check errors).

πŸ‘‹ Lifetime-License is leaving on August 10, 2026

Get it now for $29

One-time payment. Lifetime access to all pro challenges.

Loading...

Detailed Explanation

Both pieces of the solution up front:

type ReverseString<S extends string> = S extends `${infer First}${infer Rest}`
  ? `${ReverseString<Rest>}${First}`
  : ''
 
type IsPalindrome<T extends string | number> =
  `${T}` extends ReverseString<`${T}`> ? true : false

The runtime algorithm you'd write in JavaScript (reverse the input, compare it to the original) translates almost word for word into the type system.

Turning numbers into strings

The input can be a string or a number (121, 2332, ...), but string reversal only makes sense on strings. Wrapping the type parameter in a template literal, `${T}`, stringifies it: `${121}` evaluates to the string literal type '121', while a string like 'abc' passes through unchanged. Doing this once at the boundary means the rest of the solution only ever deals with strings, with no duplicated logic for the number case.

Reversing a string, one character at a time

ReverseString uses the classic recursive split:

Tracing a small input makes the flow clear:

ReverseString<'abc'>
// β†’ `${ReverseString<'bc'>}a`
// β†’ `${`${ReverseString<'c'>}b`}a`
// β†’ `${`${`${ReverseString<''>}c`}b`}a`
// β†’ 'cba'

Note that this recursion is not tail-recursive. The outer template literal still has work to do after the recursive call returns, so it hits TypeScript's depth limit at roughly 45–50 characters. For this challenge's short inputs that's plenty; if you ever need to reverse huge strings, you'd reach for an accumulator, the same way the Length of String challenges do.

The comparison

With reversal in hand, the check is a single conditional:

[object Object]

A string literal type extends another only when they're identical. So:

Edge cases the tests cover

Reverse-and-compare is a reminder that many type-level puzzles don't need clever tricks, just a faithful translation of the runtime algorithm into recursive conditional types.

This challenge is originally from here.

Share this challenge

Learn the Concepts