Absolute
Absolute
Challenge
Implement the Absolute type. A type that takes a string, number, or bigint. The output should be a positive number string.
type Test = -100
type Result = Absolute<Test> // expected to be "100"Solution
type Absolute<T extends number | string | bigint> =
`${T}` extends `-${infer N}` ? N : `${T}`The entire trick fits in one line: convert to a string, then strip a leading minus sign if present.
Step-by-step breakdown
Step 1 — Coerce everything to a string with a template literal
`${T}`TypeScript's template literal types can interpolate number, string, and bigint directly, converting their literal types into string literal types:
type A = `${-100}` // "-100"
type B = `${100}` // "100"
type C = `${-42n}` // "-42"
type D = `${"-100"}` // "-100"This single coercion handles all three accepted input types uniformly.
Step 2 — Pattern-match against a leading minus
`${T}` extends `-${infer N}` ? N : `${T}`- If the string starts with
-, TypeScript infers the remainder asN(everything after the dash) and returns it — effectively stripping the negative sign. - If it doesn't start with
-, the value is already non-negative, so we return\${T}`` unchanged.
All test cases walk-through
| Input | \${T}`` | Matches -${N}? | Result |
|---|---|---|---|
-100 | "-100" | ✅ N = "100" | "100" |
100 | "100" | ❌ | "100" |
"-100" | "-100" | ✅ N = "100" | "100" |
"100" | "100" | ❌ | "100" |
-42n | "-42" | ✅ N = "42" | "42" |
0 | "0" | ❌ | "0" |
Deep Dive
Why does the output type have to be a string?
You might expect Absolute<-100> to return the number 100, not the string "100". The reason is TypeScript's type system: while you can do arithmetic on numeric literal types in limited ways (e.g., tuple length tricks), stripping a sign character is inherently a string operation. The template literal infer pattern \-${infer N}`` can only give back a string.
If you truly needed a numeric return type you'd have to convert the resulting string back to a number, which requires the tuple-length trick and breaks for large numbers — not worth the complexity here.
Template literals as a string processing tool
This challenge demonstrates that template literal types are more than just string concatenation — they're a lightweight string parsing mechanism:
// Extract path segments
type Head<S extends string> = S extends `${infer H}/${string}` ? H : S
// Check prefix
type StartsWithA<S extends string> = S extends `A${string}` ? true : false
// Strip leading character
type StripMinus<S extends string> = S extends `-${infer R}` ? R : SThe infer keyword inside a template literal pattern is the key enabler.
Constraint: T extends number | string | bigint
Why include bigint? Because JavaScript's BigInt literals (like -42n) are their own primitive type in TypeScript. Without the bigint branch, you'd get a type error if someone passed a bigint. Template literal interpolation supports all three, so the constraint matches the capability.
What about "-0"?
Negative zero (-0) is a quirky JavaScript value. In TypeScript's type system, -0 as a numeric literal is typically treated as 0, so Absolute<-0> gives "0" — which is correct.
Why not use Math.abs-style conditional on number sign?
You could try a numeric conditional approach using conditional distribution, but TypeScript's numeric type arithmetic is very limited. You can't write T > 0 ? T : -T at the type level for arbitrary numbers. The string-based approach is the only clean solution.
Key Takeaways
- Template literals coerce
number,string, andbigintto their string equivalent at the type level — a powerful unification trick \-${infer N}`` pattern is the canonical way to strip (or detect) a leading minus sign in a type-level string- The output is always a string because sign-stripping is a string operation; converting back to a numeric type would require complex tuple arithmetic
- This challenge is a great introduction to template literal types as a parsing tool, not just a concatenation tool
- The solution works uniformly across all three input variants (
number,string,bigint) thanks to the initial coercion step
