Question
In TypeScript, what is the difference between String and string? At first glance they seem like they should represent the same kind of value, but this code behaves differently:
var a: String = "test";
var b: string = "another test";
a = b;
b = a; // compiler error
The compiler reports:
Type 'String' is not assignable to type 'string'.
'string' is a primitive, but 'String' is a wrapper object.
Prefer using 'string' when possible.
Why does this happen? Is it a bug, or is there an important difference between String and string in TypeScript?
Short Answer
By the end of this page, you will understand why string and String are not the same in TypeScript, how primitive values differ from wrapper objects, why the assignment error happens, and why developers almost always use lowercase string in real code.
Concept
In TypeScript, string and String represent related but different things.
stringis the primitive string type.Stringis the wrapper object type.
This mirrors JavaScript itself.
Primitive vs wrapper
JavaScript has primitive values such as:
stringnumberbooleanbigintsymbolnullundefined
A primitive string is a simple value:
let name: string = "Ada";
JavaScript also has object wrappers like:
StringNumber
Mental Model
Think of string as the actual text written on a note, and String as a plastic box that can hold that note.
string= the text itselfString= an object container around the text
If someone asks for a box-like thing, plain text can often still be handled because JavaScript can temporarily wrap it. But if someone asks for plain text, handing over a box is not the same thing.
That is why this feels one-way:
stringcan often act likeStringStringcannot safely act likestring
For everyday programming, you usually want the text itself, not the box.
Syntax and Examples
Core syntax
let primitiveText: string = "hello";
let wrappedText: String = new String("hello");
Recommended usage
Use lowercase string for variables, parameters, return types, and properties.
function greet(name: string): string {
return `Hello, ${name}`;
}
Example: assignment difference
let a: String = "test";
let b: string = "another test";
a = b; // OK
b = a; // Error
Why?
bis a primitive string.
Step by Step Execution
Consider this example:
let a: String = "test";
let b: string = "another test";
a = b;
b = a;
Step 1: let a: String = "test";
ais declared as typeString.- The value assigned is a primitive string:
"test". - TypeScript allows this because primitive strings can be treated like string objects in many situations.
Step 2: let b: string = "another test";
bis declared as primitive typestring.- This is the normal and recommended way to store text.
Step 3: a = b;
bcontains a primitive string.- A primitive string is acceptable for
a. - So this assignment succeeds.
Step 4: b = a;
Real World Use Cases
Where this matters in practice
Function parameters
Most functions should accept primitive strings:
function formatUsername(name: string): string {
return name.trim().toLowerCase();
}
API data
Data from APIs, forms, JSON, and databases is typically treated as primitive strings.
type User = {
email: string;
role: string;
};
Validation
When validating input, you usually check for primitive strings:
function isNonEmpty(value: string): boolean {
return value.length > 0;
}
Avoiding surprising behavior
Wrapper objects can behave unexpectedly in comparisons and truthiness.
Real Codebase Usage
In real TypeScript codebases, developers almost always use lowercase primitive types.
Common patterns
Type annotations
type Config = {
appName: string;
apiUrl: string;
};
Function contracts
function parseSlug(slug: string): string[] {
return slug.split("-");
}
Guard clauses
function printMessage(message: string) {
if (message.length === 0) {
return;
}
console.log(message);
}
Validation and normalization
function normalizeEmail(): {
email.().();
}
Common Mistakes
1. Using String instead of string
Broken example:
function greet(name: String): String {
return "Hello, " + name;
}
Better:
function greet(name: string): string {
return "Hello, " + name;
}
Why avoid it?
Stringmeans object wrapper type.- It is not the standard choice for text values.
2. Creating wrapper objects with new String()
Broken or confusing example:
const name = new String("Ada");
console.log(typeof name);
Comparisons
| Concept | string | String |
|---|---|---|
| Kind | Primitive type | Wrapper object type |
| Typical usage | Everyday text values | Rare, mostly avoided |
Runtime typeof | "string" | "object" |
| Created with | String literal like "abc" | new String("abc") |
| Recommended in TypeScript | Yes | Usually no |
| Safe for APIs/interfaces | Yes | Usually no |
Cheat Sheet
Quick rules
- Use
stringfor normal text values. - Avoid
Stringin type annotations. - Avoid
new String(). stringis primitive.Stringis an object wrapper.
Syntax
let a: string = "hello";
let b: String = new String("hello");
Assignment behavior
let x: String = "hi"; // OK
let y: string = x; // Error if x is typed as String
Runtime difference
typeof "hello" // "string"
()
FAQ
Is String the same as string in TypeScript?
No. string is a primitive type, while String is the wrapper object type.
Should I ever use String in TypeScript?
Usually no. In normal code, use string. Wrapper object types are rarely needed.
Why does a = b work but b = a fail?
Because a primitive string can be treated like a string object in some contexts, but a String object is not guaranteed to be a primitive string.
Is this a TypeScript bug?
No. It matches JavaScript's runtime behavior and TypeScript's type system.
Why can I call string methods on a primitive?
JavaScript temporarily boxes primitive strings so methods like .toUpperCase() work.
Does this apply to Number and Boolean too?
Yes. Prefer number over and over .
Mini Project
Description
Build a small TypeScript utility that accepts a user name, validates it, and formats a greeting. The goal is to practice using the primitive string type everywhere and to avoid accidental use of the String wrapper object. This reflects how text is handled in real applications such as forms, APIs, and configuration values.
Goal
Create a greeting helper that safely works with primitive strings and demonstrates why string is the correct type choice.
Requirements
- Create a function that accepts a user name as a primitive string.
- Trim extra whitespace from the input.
- Return a default greeting when the trimmed name is empty.
- Return a formatted greeting when a valid name is provided.
- Do not use
Stringornew String()anywhere in the solution.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular Dependency Injection: Fix "Can't Resolve All Parameters for Component" Errors
Learn why Angular shows "Can't resolve all parameters for component" and how to fix service injection issues in components.