| name | avoid-wrapper-types |
| description | Use when typing primitives. Use when tempted to use String, Number, Boolean. Use when wrapper types appear in errors. |
Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt)
Overview
Use lowercase primitive types, never uppercase wrapper types.
JavaScript has primitive types (string, number, boolean) and object wrapper types (String, Number, Boolean). TypeScript has types for both, but you should almost never use the wrapper types.
When to Use This Skill
- Typing any primitive value
- Seeing errors about wrapper type mismatches
- Understanding why
String !== string
- Working with methods on primitives
The Iron Rule
ALWAYS use lowercase: string, number, boolean, symbol, bigint
NEVER use uppercase: String, Number, Boolean, Symbol, BigInt
Remember:
- Wrappers are objects, primitives are not
- TypeScript freely accepts primitives where wrappers expected
- TypeScript does NOT accept wrappers where primitives expected
- Methods work on primitives via auto-boxing
Detection: The Wrapper Trap
const primitive: string = "hello";
const wrapper: String = new String("hello");
primitive === wrapper;
wrapper === wrapper;
const s1 = new String("hello");
const s2 = new String("hello");
s1 === s2;
How Primitive Methods Work
Primitives don't have methods, but this works:
'primitive'.charAt(3);
JavaScript auto-boxes:
- Creates temporary
String wrapper
- Calls method on wrapper
- Discards wrapper
- Returns result
You get convenience without the wrapper's drawbacks.
The Type Assignment Problem
const s: String = "primitive";
function takesString(s: string) { }
takesString(new String("hello"));
All Primitive Types
| Primitive (USE) | Wrapper (AVOID) |
|---|
string | String |
number | Number |
boolean | Boolean |
symbol | Symbol |
bigint | BigInt |
Note: null and undefined don't have wrapper types.
Why Wrappers Are Problematic
Identity Issues
const s1 = new String("hello");
const s2 = new String("hello");
s1 == s2;
s1 === s2;
typeof Confusion
typeof "hello";
typeof new String("hello");
Truthiness Gotchas
const falsy = new Boolean(false);
if (falsy) {
console.log("This runs!");
}
Exception: Runtime Methods
You can use wrappers for their static methods:
String.fromCharCode(65);
Number.isNaN(x);
BigInt(123);
But never use them as types or create instances.
Pressure Resistance Protocol
1. "I Need String Methods"
Pressure: "I want to use String methods, so I'll type it as String"
Response: Primitive string has all the same methods via auto-boxing.
Action: Use string type. Methods just work.
2. "TypeScript Inferred String (Uppercase)"
Pressure: "TypeScript gave me String, so it must be right"
Response: Check your code - you might be creating a wrapper accidentally.
Action: Find and fix the source. Use lowercase.
Red Flags - STOP and Reconsider
- Uppercase
String, Number, Boolean in type annotations
new String(), new Number(), new Boolean() anywhere
- Errors about wrapper vs primitive assignment
typeof x === "object" when expecting a primitive
Common Rationalizations (All Invalid)
| Excuse | Reality |
|---|
| "String has more methods" | No, both have identical methods |
| "I need an object" | You rarely do; primitives are simpler |
| "It's the same thing" | No, wrappers have identity and truthiness issues |
Quick Reference
const s: string = "hello";
const n: number = 42;
const b: boolean = true;
const sym: symbol = Symbol();
const big: bigint = 9007199254740991n;
const s: String = "hello";
const n: Number = 42;
const b: Boolean = true;
The Bottom Line
Always use lowercase primitive types.
There's never a good reason to use String, Number, or Boolean as types. The uppercase versions cause assignment errors, have identity issues, and provide no benefits over the lowercase primitives.
Reference
Based on "Effective TypeScript" by Dan Vanderkam, Item 10: Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt).