Chapter 4: TypeScript Explicit Types and Inference
TypeScript’s explicit types and inference. This is honestly one of the most fundamental concepts to understand, and once it clicks, TypeScript becomes your best friend instead of that annoying error-message machine.
Let me explain this like we’re sitting together, looking at code on a screen. I’ll show you what’s happening behind the scenes.
The Big Picture
Imagine you’re filling out a form, and there’s a field labeled “Age.”
Option A: The form has no label, just an empty box. You write “29.” The person reading it later has to guess if it’s age, apartment number, or shoe size. This is like JavaScript.
Option B: The form clearly says “Age (in years): ______” and even has a little “29” example in gray text. This is TypeScript with explicit types.
Option C: You just start writing, and the form magically knows from context that you’re probably entering an age. This is TypeScript inference.
Both Option B and C are TypeScript. Both give you that lovely blue safety net. The difference is who does the explaining – you or TypeScript.
Part 1: Explicit Types (You Take Charge)
Explicit typing is when you personally tell TypeScript, “Listen carefully. This variable is a string. Not a number, not a boolean, not an array of ponies. A. String.”
Basic Syntax
|
0 1 2 3 4 5 6 7 8 9 10 |
<span class="token keyword">let</span> myName<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">=</span> <span class="token string">"Sarah"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> myAge<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token number">28</span><span class="token punctuation">;</span> <span class="token keyword">let</span> isStudent<span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token keyword">let</span> favoriteColors<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"blue"</span><span class="token punctuation">,</span> <span class="token string">"green"</span><span class="token punctuation">,</span> <span class="token string">"purple"</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">let</span> randomThing<span class="token operator">:</span> <span class="token builtin">any</span> <span class="token operator">=</span> <span class="token string">"could be anything"</span><span class="token punctuation">;</span> <span class="token comment">// Try to avoid 'any'!</span> |
Notice the colon : followed by the type. This is you being the boss.
Why Would You Do This?
1. Clarity for yourself and others
|
0 1 2 3 4 5 6 7 8 |
<span class="token keyword">function</span> <span class="token function">calculatePrice</span><span class="token punctuation">(</span>amount<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> discount<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> amount <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> discount<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Anyone reading this knows: give me two numbers, I’ll give you a number back. No need to dig through the function body.
2. When TypeScript gets confused
Sometimes TypeScript can’t figure it out, especially with complex patterns:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="token comment">// TypeScript sees `{}` and thinks "empty object, could be anything"</span> <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// So when you try this, it complains:</span> config<span class="token punctuation">.</span>theme <span class="token operator">=</span> <span class="token string">"dark"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Property 'theme' doesn't exist on '{}'</span> <span class="token comment">// Solution? Be explicit:</span> <span class="token keyword">let</span> config<span class="token operator">:</span> <span class="token punctuation">{</span> theme<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span> theme<span class="token operator">:</span> <span class="token string">"dark"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Happy TypeScript!</span> |
3. When you want to be extra careful
|
0 1 2 3 4 5 6 7 |
<span class="token keyword">let</span> score<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> score <span class="token operator">=</span> <span class="token string">"85"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Type 'string' is not assignable to type 'number'.</span> |
TypeScript catches this mistake immediately. Without the explicit type, score would become a string, and later when you try to add 5 to it, you’d get “855” instead of 90. 🐛
Common Explicit Type Patterns
Function parameters and return types:
|
0 1 2 3 4 5 6 7 8 9 |
<span class="token keyword">function</span> <span class="token function">greetUser</span><span class="token punctuation">(</span>name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> isPremium<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> greeting <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token keyword">return</span> isPremium <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>greeting<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> Thank you for being premium!</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> greeting<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Objects:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="token keyword">let</span> person<span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> email<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// The ? means optional</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"David"</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">34</span> <span class="token comment">// email is optional, so it's okay to leave it out</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Arrays:
|
0 1 2 3 4 5 6 7 |
<span class="token keyword">let</span> numbers<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">let</span> mixed<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token builtin">string</span> <span class="token operator">|</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"hello"</span><span class="token punctuation">,</span> <span class="token number">42</span><span class="token punctuation">,</span> <span class="token string">"world"</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">;</span> |
Part 2: Type Inference (TypeScript Takes the Wheel)
Type inference is TypeScript’s superpower. It looks at your code and goes, “Ah, I see what you did there. You assigned a string to this variable, so obviously it’s a string. I’ll remember that.”
Basic Inference
|
0 1 2 3 4 5 6 7 8 |
<span class="token keyword">let</span> myName <span class="token operator">=</span> <span class="token string">"Sarah"</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript: "Aha! This is a string!"</span> <span class="token keyword">let</span> myAge <span class="token operator">=</span> <span class="token number">28</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript: "Got it, this one's a number"</span> <span class="token keyword">let</span> isStudent <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript: "Boolean, check!"</span> |
I didn’t write : string, but TypeScript still knows. Hover over myName in your editor – it shows let myName: string. It inferred the type from the value.
How Inference Works
TypeScript is constantly analyzing your code, connecting dots:
From initial values:
|
0 1 2 3 4 5 6 7 8 9 10 |
<span class="token keyword">let</span> message <span class="token operator">=</span> <span class="token string">"Welcome!"</span><span class="token punctuation">;</span> <span class="token comment">// Inferred as string</span> message <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span> <span class="token comment">// Error! TypeScript now says "Hey, I thought this was a string!"</span> <span class="token keyword">let</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Inferred as number[]</span> items<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"4"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Error! Can't push string into number[]</span> |
From function returns:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="token keyword">function</span> <span class="token function">add</span><span class="token punctuation">(</span>x<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> y<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">+</span> y<span class="token punctuation">;</span> <span class="token comment">// TypeScript infers return type as number</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">getGreeting</span><span class="token punctuation">(</span>name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token comment">// Infers return type as string</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">getValue</span><span class="token punctuation">(</span>condition<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>condition<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"yes"</span><span class="token punctuation">;</span> <span class="token comment">// string</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// number</span> <span class="token punctuation">}</span> <span class="token comment">// Infers return type as string | number (union type)</span> |
From context (contextual typing):
|
0 1 2 3 4 5 6 7 8 9 10 |
<span class="token comment">// TypeScript knows this event is a mouse event on a button</span> <span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> button<span class="token operator">?.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>event<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>clientX<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript knows 'event' has clientX property</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Part 3: The Beautiful Dance – When to Use What
Here’s where it gets practical. How do you decide between explicit and inferred?
✅ Perfect for Inference:
Simple variable initialization:
|
0 1 2 3 4 5 6 7 |
<span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token string">"John"</span><span class="token punctuation">;</span> <span class="token comment">// Clean, obvious</span> <span class="token keyword">const</span> <span class="token constant">PI</span> <span class="token operator">=</span> <span class="token number">3.14159</span><span class="token punctuation">;</span> <span class="token comment">// Even better with const</span> |
Simple function returns:
|
0 1 2 3 4 5 6 7 8 |
<span class="token keyword">function</span> <span class="token function">multiply</span><span class="token punctuation">(</span>a<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> b<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> a <span class="token operator">*</span> b<span class="token punctuation">;</span> <span class="token comment">// Clearly returns a number</span> <span class="token punctuation">}</span> |
Default values in parameters:
|
0 1 2 3 4 5 6 7 8 |
<span class="token keyword">function</span> <span class="token function">createGrid</span><span class="token punctuation">(</span>size <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// size is number</span> <span class="token keyword">return</span> <span class="token function">Array</span><span class="token punctuation">(</span>size<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
✅ Better to be Explicit:
Function parameters (always!):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="token comment">// ❌ Don't do this</span> <span class="token keyword">function</span> <span class="token function">processData</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 'data' is implicitly 'any' - TypeScript isn't helping!</span> <span class="token keyword">return</span> data<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// ✅ Do this</span> <span class="token keyword">function</span> <span class="token function">processData</span><span class="token punctuation">(</span>data<span class="token operator">:</span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Clear contract</span> <span class="token keyword">return</span> data<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Complex objects:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="token comment">// ❌ TypeScript infers: { name: string; age: number }</span> <span class="token comment">// That's fine... until you add another property</span> <span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"Alice"</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">30</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> user<span class="token punctuation">.</span>isAdmin <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">// Error! TypeScript didn't know about isAdmin</span> <span class="token comment">// ✅ Define the shape clearly</span> <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> isAdmin<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> user<span class="token operator">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"Alice"</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">30</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Now you can add isAdmin later</span> |
Variables with no initial value:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<span class="token comment">// ❌ TypeScript sees: let data: any (dangerous!)</span> <span class="token keyword">let</span> data<span class="token punctuation">;</span> data <span class="token operator">=</span> <span class="token function">fetchSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Could be anything</span> <span class="token comment">// ✅ Be safe</span> <span class="token keyword">let</span> data<span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// I know it will be string or null</span> |
When the type isn’t obvious:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="token comment">// What does this return? I'd have to read carefully</span> <span class="token keyword">function</span> <span class="token function">processItems</span><span class="token punctuation">(</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>item <span class="token operator">=></span> item<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Much clearer!</span> <span class="token keyword">function</span> <span class="token function">processItems</span><span class="token punctuation">(</span>items<span class="token operator">:</span> Item<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> items<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>item <span class="token operator">=></span> item<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Part 4: Common Confusions (Let’s Clear Them Up)
“But I wrote the type, why is TypeScript still mad?”
|
0 1 2 3 4 5 6 7 8 9 10 |
<span class="token comment">// This seems redundant to beginners:</span> <span class="token keyword">let</span> count<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token comment">// Explicit</span> <span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token comment">// Inferred</span> <span class="token comment">// They do the same thing! So use inference here. Save explicit for when it matters.</span> |
“TypeScript keeps inferring ‘any’ and I don’t know why!”
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="token comment">// When you declare without initializing AND without type</span> <span class="token keyword">let</span> mystery<span class="token punctuation">;</span> <span class="token comment">// TypeScript throws hands up: 🤷♂️ 'any'</span> mystery <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span> mystery <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span> <span class="token comment">// No error - that's the problem!</span> <span class="token comment">// Fix it:</span> <span class="token keyword">let</span> mystery<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// Now TypeScript will enforce it's a string</span> mystery <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span> mystery <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span> <span class="token comment">// Error! Gotcha! 🎯</span> |
“Wait, but sometimes I see TypeScript inferring something super complex!”
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span class="token keyword">const</span> statuses <span class="token operator">=</span> <span class="token punctuation">{</span> pending<span class="token operator">:</span> <span class="token string">"PENDING"</span><span class="token punctuation">,</span> approved<span class="token operator">:</span> <span class="token string">"APPROVED"</span><span class="token punctuation">,</span> rejected<span class="token operator">:</span> <span class="token string">"REJECTED"</span> <span class="token punctuation">}</span> <span class="token keyword">as</span> <span class="token keyword">const</span><span class="token punctuation">;</span> <span class="token comment">// This is a special inference trick</span> <span class="token comment">// Without 'as const': type is { pending: string; approved: string; rejected: string }</span> <span class="token comment">// With 'as const': type is { readonly pending: "PENDING"; readonly approved: "APPROVED"; readonly rejected: "REJECTED" }</span> <span class="token comment">// Much more specific!</span> |
Part 5: Let’s Practice – Real World Examples
Example 1: A Shopping Cart
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span class="token comment">// Explicit for the structure</span> <span class="token keyword">interface</span> <span class="token class-name">CartItem</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> price<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> quantity<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Inference for the values</span> <span class="token keyword">let</span> cart<span class="token operator">:</span> CartItem<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// I'm explicit about cart being an array of CartItems</span> cart<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"TypeScript Handbook"</span><span class="token punctuation">,</span> price<span class="token operator">:</span> <span class="token number">39.99</span><span class="token punctuation">,</span> quantity<span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// The object itself can be inferred</span> <span class="token comment">// Inference works great here</span> <span class="token keyword">function</span> <span class="token function">calculateTotal</span><span class="token punctuation">(</span>cart<span class="token operator">:</span> CartItem<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> cart<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span>sum<span class="token punctuation">,</span> item<span class="token punctuation">)</span> <span class="token operator">=></span> sum <span class="token operator">+</span> item<span class="token punctuation">.</span>price <span class="token operator">*</span> item<span class="token punctuation">.</span>quantity<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// TypeScript infers return type as number - perfect!</span> |
Example 2: API Response
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="token comment">// Explicit - I want to define the contract</span> <span class="token keyword">interface</span> <span class="token class-name">APIResponse<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token punctuation">{</span> data<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span> status<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> message<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Inference for implementation</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchUser</span><span class="token punctuation">(</span>id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/api/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> data<span class="token operator">:</span> APIResponse<span class="token operator"><</span>User<span class="token operator">></span> <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Explicit at edge</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token comment">// TypeScript knows this is APIResponse<User></span> <span class="token punctuation">}</span> |
The Golden Rule I Tell My Students
“Be explicit at boundaries, embrace inference everywhere else.”
What are boundaries?
-
Function parameters (what comes in)
-
Function return types (what goes out, especially in public APIs)
-
Object/interface definitions (the shape of your data)
-
Variables declared without initial values
What’s “everywhere else”?
-
Local variables with clear initial values
-
Simple function returns
-
Loop variables
-
Callback parameters
Final Thoughts
TypeScript inference is like having an incredibly smart assistant who usually knows what you mean. Explicit types are you being the architect and drawing up detailed blueprints.
Neither is “better” – they’re tools for different situations. The best TypeScript code uses both harmoniously: explicit where clarity matters most, inference where the intent is obvious.
Start paying attention to what TypeScript infers. Hover over variables in your editor. You’ll develop intuition for when inference is enough and when you need to be explicit. And remember – the goal isn’t to write the most types, but to write the most understandable and correct code.
Does this make sense? I’d be happy to dive deeper into any specific part or show more examples!
