Chapter 8: TypeScript Object Types
Part 1: The Basics – What Is an Object Type?
An object type describes the shape of a JavaScript object – what properties it has and what types those properties are.
The Simplest Object Type
|
0 1 2 3 4 5 6 7 8 9 |
<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 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> <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> |
That’s it! { name: string; age: number } is an object type. It says:
-
This object MUST have a property called
namethat is a string -
This object MUST have a property called
agethat is a number -
It CANNOT have any other properties (with some caveats we’ll discuss)
Syntax Options
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="token comment">// You can use semicolons:</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 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><span class="token punctuation">;</span> <span class="token comment">// You can use commas:</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 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><span class="token punctuation">;</span> <span class="token comment">// You can split across lines:</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 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> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// All are equivalent - pick what you prefer!</span> |
Part 2: Optional Properties
Not everything is required. Use ? to mark optional properties:
|
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 |
<span class="token keyword">interface</span> <span class="token class-name">Product</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> description<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">// Optional</span> category<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">// Optional</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> product1<span class="token operator">:</span> Product <span class="token operator">=</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">"Laptop"</span><span class="token punctuation">,</span> price<span class="token operator">:</span> <span class="token number">999</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Valid - description and category are optional</span> <span class="token keyword">let</span> product2<span class="token operator">:</span> Product <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">"Mouse"</span><span class="token punctuation">,</span> price<span class="token operator">:</span> <span class="token number">29</span><span class="token punctuation">,</span> description<span class="token operator">:</span> <span class="token string">"Wireless optical mouse"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Also valid</span> |
What optional really means:
-
The property CAN be missing
-
If present, it MUST be the correct type
-
Its type is actually
string | undefined
|
0 1 2 3 4 5 6 7 |
product<span class="token punctuation">.</span>description <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> <span class="token comment">// ✓ This is allowed!</span> product<span class="token punctuation">.</span>description <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span> <span class="token comment">// Error! Type 'number' is not assignable to type 'string | undefined'</span> |
Part 3: Readonly Properties
Sometimes you want properties that cannot be changed after creation:
|
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 |
<span class="token keyword">interface</span> <span class="token class-name">Config</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> apiKey<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token keyword">readonly</span> endpoint<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> timeout<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// Not readonly - can be changed</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> config<span class="token operator">:</span> Config <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey<span class="token operator">:</span> <span class="token string">"abc-123-def"</span><span class="token punctuation">,</span> endpoint<span class="token operator">:</span> <span class="token string">"https://api.example.com"</span><span class="token punctuation">,</span> timeout<span class="token operator">:</span> <span class="token number">5000</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> config<span class="token punctuation">.</span>timeout <span class="token operator">=</span> <span class="token number">10000</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works - timeout is mutable</span> config<span class="token punctuation">.</span>apiKey <span class="token operator">=</span> <span class="token string">"new-key"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Cannot assign to 'apiKey' because it is a read-only property</span> <span class="token comment">// This is especially useful for:</span> <span class="token comment">// - Configuration objects</span> <span class="token comment">// - Domain entities with IDs</span> <span class="token comment">// - Constants</span> <span class="token comment">// - Values that shouldn't change after initialization</span> |
Readonly vs Const
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<span class="token comment">// const prevents reassignment of the variable</span> <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey<span class="token operator">:</span> <span class="token string">"123"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey<span class="token operator">:</span> <span class="token string">"456"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Error! Can't reassign config</span> config<span class="token punctuation">.</span>apiKey <span class="token operator">=</span> <span class="token string">"456"</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works - property is mutable!</span> <span class="token comment">// readonly prevents reassignment of the property</span> <span class="token keyword">interface</span> <span class="token class-name">Config</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> apiKey<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">let</span> config<span class="token operator">:</span> Config <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey<span class="token operator">:</span> <span class="token string">"123"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> config<span class="token punctuation">.</span>apiKey <span class="token operator">=</span> <span class="token string">"456"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Can't reassign property</span> config <span class="token operator">=</span> <span class="token punctuation">{</span> apiKey<span class="token operator">:</span> <span class="token string">"456"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works - variable can be reassigned</span> |
Part 4: Index Signatures – Dynamic Properties
What if you don’t know the property names in advance? Enter index signatures:
|
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 27 28 29 30 31 32 33 |
<span class="token comment">// A dictionary of string keys to number values</span> <span class="token keyword">interface</span> <span class="token class-name">Scoreboard</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>playerName<span class="token operator">:</span> <span class="token builtin">string</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 punctuation">}</span> <span class="token keyword">let</span> scores<span class="token operator">:</span> Scoreboard <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string-property property">"Alice"</span><span class="token operator">:</span> <span class="token number">95</span><span class="token punctuation">,</span> <span class="token string-property property">"Bob"</span><span class="token operator">:</span> <span class="token number">87</span><span class="token punctuation">,</span> <span class="token string-property property">"Charlie"</span><span class="token operator">:</span> <span class="token number">92</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> scores<span class="token punctuation">[</span><span class="token string">"David"</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">88</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works</span> scores<span class="token punctuation">.</span>Eve <span class="token operator">=</span> <span class="token number">91</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Also works with dot notation</span> <span class="token comment">// You can mix known and dynamic properties</span> <span class="token keyword">interface</span> <span class="token class-name">StudentGrades</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token builtin">string</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>subject<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">:</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 comment">// Dynamic properties must be string or number</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> student<span class="token operator">:</span> StudentGrades <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> id<span class="token operator">:</span> <span class="token number">12345</span><span class="token punctuation">,</span> math<span class="token operator">:</span> <span class="token string">"A"</span><span class="token punctuation">,</span> science<span class="token operator">:</span> <span class="token string">"B+"</span><span class="token punctuation">,</span> history<span class="token operator">:</span> <span class="token string">"A-"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
The Catch with Index Signatures
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="token keyword">interface</span> <span class="token class-name">Dictionary</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>key<span class="token operator">:</span> <span class="token builtin">string</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 comment">// length: number; // Error! Property 'length' of type 'number' is not assignable to 'string' index type 'string'</span> <span class="token punctuation">}</span> <span class="token comment">// Fix: Use a union type</span> <span class="token class-name"><span class="token keyword">interface</span></span> Dictionary <span class="token punctuation">{</span> <span class="token punctuation">[</span>key<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token builtin">number</span><span class="token punctuation">;</span> length<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works now</span> <span class="token punctuation">}</span> |
Part 5: Nested Object Types
Objects contain other objects. TypeScript handles this naturally:
|
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<span class="token keyword">interface</span> <span class="token class-name">Address</span> <span class="token punctuation">{</span> street<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> city<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> country<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> postalCode<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">interface</span> <span class="token class-name">User</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> email<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> address<span class="token operator">:</span> Address<span class="token punctuation">;</span> <span class="token comment">// Nested object</span> preferences<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">{</span> theme<span class="token operator">:</span> <span class="token string">"light"</span> <span class="token operator">|</span> <span class="token string">"dark"</span><span class="token punctuation">;</span> notifications<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> language<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 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> 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">"Alice"</span><span class="token punctuation">,</span> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</span><span class="token punctuation">,</span> address<span class="token operator">:</span> <span class="token punctuation">{</span> street<span class="token operator">:</span> <span class="token string">"123 Main St"</span><span class="token punctuation">,</span> city<span class="token operator">:</span> <span class="token string">"Boston"</span><span class="token punctuation">,</span> country<span class="token operator">:</span> <span class="token string">"USA"</span><span class="token punctuation">,</span> postalCode<span class="token operator">:</span> <span class="token string">"02108"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> preferences<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> notifications<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> language<span class="token operator">:</span> <span class="token string">"en"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Deep access with full type safety</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>address<span class="token punctuation">.</span>city<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ✓ TypeScript knows this is string</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>preferences<span class="token operator">?.</span>theme<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Optional chaining works perfectly</span> |
Part 6: Type Aliases vs Interfaces
You’ve seen both type and interface. What’s the difference?
Type Aliases
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="token keyword">type</span> <span class="token class-name">User</span> <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> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">type</span> <span class="token class-name"><span class="token constant">ID</span></span> <span class="token operator">=</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 comment">// Can do this with type, not interface</span> <span class="token class-name"><span class="token keyword">type</span></span> <span class="token function-variable function">Callback</span> <span class="token operator">=</span> <span class="token punctuation">(</span>error<span class="token operator">:</span> Error <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">,</span> data<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">;</span> <span class="token comment">// Function types</span> <span class="token keyword">type</span> <span class="token class-name">Nested<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token constant">T</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Generics work with both</span> |
Interfaces
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<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> <span class="token punctuation">}</span> <span class="token comment">// Can extend (inherit)</span> <span class="token keyword">interface</span> <span class="token class-name">Employee</span> <span class="token keyword">extends</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> employeeId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> department<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">// Can be merged (declaration merging) - THIS IS UNIQUE TO INTERFACES</span> <span class="token keyword">interface</span> <span class="token class-name">User</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">// Adds email to User interface</span> <span class="token punctuation">}</span> <span class="token comment">// Now User has name, age, and optional email</span> |
Which to Use?
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="token comment">// ✅ Use interface for:</span> <span class="token comment">// - Object shapes that might be extended later</span> <span class="token comment">// - When you want declaration merging</span> <span class="token comment">// - Public APIs and libraries</span> <span class="token comment">// ✅ Use type for:</span> <span class="token comment">// - Union types</span> <span class="token comment">// - Function types</span> <span class="token comment">// - Complex generics</span> <span class="token comment">// - When you need computed properties</span> |
My rule of thumb: Start with interface for objects, switch to type when you need its specific features.
Part 7: Excess Property Checking
This trips up many beginners. TypeScript has a special behavior when you assign object literals directly:
|
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 27 28 29 30 31 |
<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> <span class="token punctuation">}</span> <span class="token comment">// ❌ This is an error:</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> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</span> <span class="token comment">// Error! Object literal may only specify known properties</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// ✅ This is NOT an error:</span> <span class="token keyword">let</span> userData <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> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</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> userData<span class="token punctuation">;</span> <span class="token comment">// ✓ Works! TypeScript checks that User requirements are met</span> <span class="token comment">// ✅ This is also fine:</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 operator">...</span><span class="token punctuation">{</span> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</span> <span class="token punctuation">}</span> <span class="token comment">// Spread operator "hides" the excess property</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Why? Direct object literals get extra scrutiny because they’re likely mistakes. Once assigned to another variable, TypeScript assumes you know what you’re doing.
Part 8: Freshness and Type Widening
When you create object literals, TypeScript tracks them precisely:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="token comment">// This object is "fresh" - TypeScript knows exactly what properties it has</span> <span class="token keyword">let</span> alice <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> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// TypeScript infers: { name: string; age: number; email: string }</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 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> <span class="token operator">=</span> alice<span class="token punctuation">;</span> <span class="token comment">// ✓ Works - it's compatible</span> <span class="token comment">// But if we try to add a property later:</span> alice<span class="token punctuation">.</span>phone <span class="token operator">=</span> <span class="token string">"555-1234"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Property 'phone' does not exist on inferred type</span> |
Solution: Define the type upfront if you plan to add properties:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<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> email<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> phone<span class="token operator">?</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 keyword">let</span> alice<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> email<span class="token operator">:</span> <span class="token string">"alice@example.com"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> alice<span class="token punctuation">.</span>phone <span class="token operator">=</span> <span class="token string">"555-1234"</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works now</span> |
Part 9: Methods in Object Types
Objects can have functions. TypeScript types them too:
|
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 27 28 29 30 31 32 33 34 35 |
<span class="token keyword">interface</span> <span class="token class-name">Calculator</span> <span class="token punctuation">{</span> <span class="token comment">// Method syntax (recommended)</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 operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// Property with function type</span> <span class="token class-name">subtract</span><span class="token operator">:</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 operator">=></span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// Optional method</span> multiply<span class="token operator">?</span><span class="token operator">:</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 operator">=></span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> calculator<span class="token operator">:</span> Calculator <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token function">add</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<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 punctuation">}</span><span class="token punctuation">,</span> <span class="token function">subtract</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<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 punctuation">}</span> <span class="token comment">// multiply is optional, so it's okay to omit</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Method signatures can include this parameter</span> <span class="token keyword">interface</span> <span class="token class-name">DOMElement</span> <span class="token punctuation">{</span> textContent<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token function">addEventListener</span><span class="token punctuation">(</span> <span class="token keyword">this</span><span class="token operator">:</span> DOMElement<span class="token punctuation">,</span> <span class="token comment">// 'this' is guaranteed to be DOMElement</span> type<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token function-variable function">listener</span><span class="token operator">:</span> <span class="token punctuation">(</span>event<span class="token operator">:</span> Event<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span> <span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Part 10: Generic Object Types
Objects can work with any type using generics:
|
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 27 28 29 30 31 32 |
<span class="token comment">// A generic Box that can hold any type</span> <span class="token keyword">interface</span> <span class="token class-name">Box<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span> timestamp<span class="token operator">:</span> Date<span class="token punctuation">;</span> metadata<span class="token operator">?</span><span class="token operator">:</span> Record<span class="token operator"><</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">any</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> stringBox<span class="token operator">:</span> Box<span class="token operator"><</span><span class="token builtin">string</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token string">"hello"</span><span class="token punctuation">,</span> timestamp<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">let</span> numberBox<span class="token operator">:</span> Box<span class="token operator"><</span><span class="token builtin">number</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token number">42</span><span class="token punctuation">,</span> timestamp<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Generic function with object type</span> <span class="token class-name"><span class="token keyword">function</span></span> <span class="token generic-function"><span class="token function">wrapInBox</span><span class="token generic class-name"><span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span></span><span class="token punctuation">(</span>value<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span><span class="token operator">:</span> Box<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> value<span class="token punctuation">,</span> timestamp<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> box <span class="token operator">=</span> <span class="token function">wrapInBox</span><span class="token punctuation">(</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 punctuation">;</span> <span class="token comment">// TypeScript infers: Box<{ name: string; age: number }></span> |
Real-World: API Response Wrapper
|
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 27 28 29 |
<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> timestamp<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">PaginatedResponse<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><span class="token punctuation">]</span><span class="token punctuation">;</span> page<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> totalPages<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> totalItems<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> hasMore<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">interface</span> <span class="token class-name">User</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> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchUsers</span><span class="token punctuation">(</span>page<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">Promise</span><span class="token operator"><</span>ApiResponse<span class="token operator"><</span>PaginatedResponse<span class="token operator"><</span>User<span class="token operator">>>></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?page=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>page<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">return</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 punctuation">}</span> |
Part 11: Advanced Object Type Patterns
Discriminated Unions
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<span class="token keyword">type</span> <span class="token class-name">Shape</span> <span class="token operator">=</span> <span class="token operator">|</span> <span class="token punctuation">{</span> kind<span class="token operator">:</span> <span class="token string">"circle"</span><span class="token punctuation">;</span> radius<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token punctuation">{</span> kind<span class="token operator">:</span> <span class="token string">"rectangle"</span><span class="token punctuation">;</span> width<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> height<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token punctuation">{</span> kind<span class="token operator">:</span> <span class="token string">"square"</span><span class="token punctuation">;</span> size<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">function</span> <span class="token function">getArea</span><span class="token punctuation">(</span>shape<span class="token operator">:</span> Shape<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">switch</span> <span class="token punctuation">(</span>shape<span class="token punctuation">.</span>kind<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">"circle"</span><span class="token operator">:</span> <span class="token keyword">return</span> Math<span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">*</span> shape<span class="token punctuation">.</span>radius <span class="token operator">**</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"rectangle"</span><span class="token operator">:</span> <span class="token keyword">return</span> shape<span class="token punctuation">.</span>width <span class="token operator">*</span> shape<span class="token punctuation">.</span>height<span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"square"</span><span class="token operator">:</span> <span class="token keyword">return</span> shape<span class="token punctuation">.</span>size <span class="token operator">*</span> shape<span class="token punctuation">.</span>size<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Utility Types for Objects
|
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 27 28 29 30 31 |
<span class="token keyword">interface</span> <span class="token class-name">User</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> email<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> password<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> createdAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Make all properties optional</span> <span class="token keyword">type</span> <span class="token class-name">PartialUser</span> <span class="token operator">=</span> Partial<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Make all properties required</span> <span class="token keyword">type</span> <span class="token class-name">RequiredUser</span> <span class="token operator">=</span> Required<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Make all properties readonly</span> <span class="token keyword">type</span> <span class="token class-name">ReadonlyUser</span> <span class="token operator">=</span> Readonly<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Pick specific properties</span> <span class="token keyword">type</span> <span class="token class-name">UserCredentials</span> <span class="token operator">=</span> Pick<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">"email"</span> <span class="token operator">|</span> <span class="token string">"password"</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Omit specific properties</span> <span class="token keyword">type</span> <span class="token class-name">PublicUser</span> <span class="token operator">=</span> Omit<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">"password"</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Record - create object type from union</span> <span class="token keyword">type</span> <span class="token class-name">UserRoles</span> <span class="token operator">=</span> Record<span class="token operator"><</span><span class="token string">"admin"</span> <span class="token operator">|</span> <span class="token string">"editor"</span> <span class="token operator">|</span> <span class="token string">"viewer"</span><span class="token punctuation">,</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 comment">// Equivalent to: { admin: string[]; editor: string[]; viewer: string[] }</span> |
Intersection Types
|
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 27 28 |
<span class="token keyword">interface</span> <span class="token class-name">BasicInfo</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> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">ContactInfo</span> <span class="token punctuation">{</span> email<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> phone<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">type</span> <span class="token class-name">Employee</span> <span class="token operator">=</span> BasicInfo <span class="token operator">&</span> ContactInfo <span class="token operator">&</span> <span class="token punctuation">{</span> employeeId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> department<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">let</span> employee<span class="token operator">:</span> Employee <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> email<span class="token operator">:</span> <span class="token string">"alice@company.com"</span><span class="token punctuation">,</span> phone<span class="token operator">:</span> <span class="token string">"555-1234"</span><span class="token punctuation">,</span> employeeId<span class="token operator">:</span> <span class="token string">"E12345"</span><span class="token punctuation">,</span> department<span class="token operator">:</span> <span class="token string">"Engineering"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Part 12: Real-World Case Study – E-Commerce System
Let’s build a complete e-commerce system to see how object types work together:
|
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
<span class="token comment">// Base domain entities</span> <span class="token keyword">interface</span> <span class="token class-name">Product</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> description<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> price<span class="token operator">:</span> Money<span class="token punctuation">;</span> category<span class="token operator">:</span> Category<span class="token punctuation">;</span> inventory<span class="token operator">:</span> Inventory<span class="token punctuation">;</span> metadata<span class="token operator">?</span><span class="token operator">:</span> ProductMetadata<span class="token punctuation">;</span> <span class="token keyword">readonly</span> createdAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token keyword">readonly</span> updatedAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Money</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token operator">|</span> <span class="token string">"EUR"</span> <span class="token operator">|</span> <span class="token string">"GBP"</span> <span class="token operator">|</span> <span class="token string">"JPY"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Category</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> parentId<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> slug<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">interface</span> <span class="token class-name">Inventory</span> <span class="token punctuation">{</span> quantity<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> lowStockThreshold<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> reserved<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token keyword">readonly</span> available<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token comment">// Computed field</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">ProductMetadata</span> <span class="token punctuation">{</span> tags<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> weight<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> dimensions<span class="token operator">?</span><span class="token operator">:</span> Dimensions<span class="token punctuation">;</span> images<span class="token operator">?</span><span class="token operator">:</span> Image<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> variants<span class="token operator">?</span><span class="token operator">:</span> ProductVariant<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Dimensions</span> <span class="token punctuation">{</span> length<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> width<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> height<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> unit<span class="token operator">:</span> <span class="token string">"cm"</span> <span class="token operator">|</span> <span class="token string">"in"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Image</span> <span class="token punctuation">{</span> url<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> alt<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> width<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> height<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> isPrimary<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">interface</span> <span class="token class-name">ProductVariant</span> <span class="token punctuation">{</span> sku<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> attributes<span class="token operator">:</span> Record<span class="token operator"><</span><span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token builtin">string</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// e.g., { "color": "red", "size": "large" }</span> price<span class="token operator">:</span> Money<span class="token punctuation">;</span> inventory<span class="token operator">:</span> Inventory<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Shopping cart with discriminated union for items</span> <span class="token keyword">type</span> <span class="token class-name">CartItem</span> <span class="token operator">=</span> <span class="token operator">|</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"product"</span><span class="token punctuation">;</span> productId<span class="token operator">:</span> <span class="token builtin">string</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 operator">|</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"variant"</span><span class="token punctuation">;</span> productId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> variantSku<span class="token operator">:</span> <span class="token builtin">string</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 keyword">interface</span> <span class="token class-name">Cart</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> userId<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">// Optional for guest carts</span> items<span class="token operator">:</span> CartItem<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> coupon<span class="token operator">?</span><span class="token operator">:</span> Coupon<span class="token punctuation">;</span> subtotal<span class="token operator">:</span> Money<span class="token punctuation">;</span> tax<span class="token operator">:</span> Money<span class="token punctuation">;</span> shipping<span class="token operator">:</span> Money<span class="token punctuation">;</span> total<span class="token operator">:</span> Money<span class="token punctuation">;</span> updatedAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Coupon</span> <span class="token punctuation">{</span> code<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> discountType<span class="token operator">:</span> <span class="token string">"percentage"</span> <span class="token operator">|</span> <span class="token string">"fixed"</span><span class="token punctuation">;</span> discountValue<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> minimumPurchase<span class="token operator">?</span><span class="token operator">:</span> Money<span class="token punctuation">;</span> validFrom<span class="token operator">:</span> Date<span class="token punctuation">;</span> validUntil<span class="token operator">:</span> Date<span class="token punctuation">;</span> usageLimit<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> usedCount<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">// Order with state machine</span> <span class="token keyword">type</span> <span class="token class-name">OrderStatus</span> <span class="token operator">=</span> <span class="token operator">|</span> <span class="token punctuation">{</span> state<span class="token operator">:</span> <span class="token string">"pending"</span> <span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token punctuation">{</span> state<span class="token operator">:</span> <span class="token string">"paid"</span><span class="token punctuation">;</span> paidAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> transactionId<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> state<span class="token operator">:</span> <span class="token string">"shipped"</span><span class="token punctuation">;</span> shippedAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> trackingNumber<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> state<span class="token operator">:</span> <span class="token string">"delivered"</span><span class="token punctuation">;</span> deliveredAt<span class="token operator">:</span> Date <span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token punctuation">{</span> state<span class="token operator">:</span> <span class="token string">"cancelled"</span><span class="token punctuation">;</span> cancelledAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> reason<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">interface</span> <span class="token class-name">Order</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> userId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> items<span class="token operator">:</span> <span class="token punctuation">{</span> productId<span class="token operator">:</span> <span class="token builtin">string</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> Money<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 punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> shippingAddress<span class="token operator">:</span> Address<span class="token punctuation">;</span> billingAddress<span class="token operator">:</span> Address<span class="token punctuation">;</span> paymentMethod<span class="token operator">:</span> PaymentMethod<span class="token punctuation">;</span> status<span class="token operator">:</span> OrderStatus<span class="token punctuation">;</span> subtotal<span class="token operator">:</span> Money<span class="token punctuation">;</span> tax<span class="token operator">:</span> Money<span class="token punctuation">;</span> shipping<span class="token operator">:</span> Money<span class="token punctuation">;</span> total<span class="token operator">:</span> Money<span class="token punctuation">;</span> createdAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> updatedAt<span class="token operator">:</span> Date<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">Address</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> line1<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> line2<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> city<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> state<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> postalCode<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> country<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> phone<span class="token operator">?</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 keyword">type</span> <span class="token class-name">PaymentMethod</span> <span class="token operator">=</span> <span class="token operator">|</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"creditCard"</span><span class="token punctuation">;</span> last4<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> brand<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> expiryMonth<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> expiryYear<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">}</span> <span class="token operator">|</span> <span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"paypal"</span><span class="token punctuation">;</span> email<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> type<span class="token operator">:</span> <span class="token string">"giftCard"</span><span class="token punctuation">;</span> code<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> balance<span class="token operator">:</span> Money <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Services with method signatures</span> <span class="token keyword">interface</span> <span class="token class-name">ProductService</span> <span class="token punctuation">{</span> <span class="token function">findById</span><span class="token punctuation">(</span>id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Product <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token function">findByCategory</span><span class="token punctuation">(</span>categoryId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Product<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token function">search</span><span class="token punctuation">(</span>query<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> filters<span class="token operator">?</span><span class="token operator">:</span> ProductFilters<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>PaginatedResponse<span class="token operator"><</span>Product<span class="token operator">>></span><span class="token punctuation">;</span> <span class="token function">create</span><span class="token punctuation">(</span>product<span class="token operator">:</span> Omit<span class="token operator"><</span>Product<span class="token punctuation">,</span> <span class="token string">"id"</span> <span class="token operator">|</span> <span class="token string">"createdAt"</span> <span class="token operator">|</span> <span class="token string">"updatedAt"</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Product<span class="token operator">></span><span class="token punctuation">;</span> <span class="token function">update</span><span class="token punctuation">(</span>id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> updates<span class="token operator">:</span> Partial<span class="token operator"><</span>Product<span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Product<span class="token operator">></span><span class="token punctuation">;</span> <span class="token keyword">delete</span><span class="token punctuation">(</span>id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token keyword">void</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">ProductFilters</span> <span class="token punctuation">{</span> minPrice<span class="token operator">?</span><span class="token operator">:</span> Money<span class="token punctuation">;</span> maxPrice<span class="token operator">?</span><span class="token operator">:</span> Money<span class="token punctuation">;</span> categoryId<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> inStock<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> tags<span class="token operator">?</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 punctuation">}</span> <span class="token keyword">interface</span> <span class="token class-name">PaginatedResponse<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><span class="token punctuation">]</span><span class="token punctuation">;</span> page<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> limit<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> total<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> hasNext<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> hasPrev<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Implementation example</span> <span class="token keyword">class</span> <span class="token class-name">ShoppingCartService</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> carts<span class="token operator">:</span> Map<span class="token operator"><</span><span class="token builtin">string</span><span class="token punctuation">,</span> Cart<span class="token operator">></span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token function">addToCart</span><span class="token punctuation">(</span>cartId<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> item<span class="token operator">:</span> CartItem<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Cart<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">let</span> cart <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>carts<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>cartId<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>cart<span class="token punctuation">)</span> <span class="token punctuation">{</span> cart <span class="token operator">=</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> cartId<span class="token punctuation">,</span> items<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> subtotal<span class="token operator">:</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> tax<span class="token operator">:</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> shipping<span class="token operator">:</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> total<span class="token operator">:</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> updatedAt<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Add item and recalculate</span> cart<span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">recalculateCart</span><span class="token punctuation">(</span>cart<span class="token punctuation">)</span><span class="token punctuation">;</span> cart<span class="token punctuation">.</span>updatedAt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>carts<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>cartId<span class="token punctuation">,</span> cart<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 punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">async</span> <span class="token function">recalculateCart</span><span class="token punctuation">(</span>cart<span class="token operator">:</span> Cart<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token keyword">void</span><span class="token operator">></span> <span class="token punctuation">{</span> <span class="token comment">// Complex business logic here</span> <span class="token comment">// TypeScript ensures we handle all cases correctly</span> <span class="token keyword">let</span> subtotal <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> item <span class="token keyword">of</span> cart<span class="token punctuation">.</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>item<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">"product"</span><span class="token operator">:</span> <span class="token comment">// Fetch product and calculate</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"variant"</span><span class="token operator">:</span> <span class="token comment">// Fetch variant and calculate</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> cart<span class="token punctuation">.</span>subtotal <span class="token operator">=</span> <span class="token punctuation">{</span> amount<span class="token operator">:</span> subtotal<span class="token punctuation">,</span> currency<span class="token operator">:</span> <span class="token string">"USD"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// ... calculate tax, shipping, apply coupons</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Part 13: Common Pitfalls and Solutions
Pitfall 1: Assuming Objects Are Fully Sealed
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<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> <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> user<span class="token punctuation">.</span>anyProperty <span class="token operator">=</span> <span class="token string">"value"</span><span class="token punctuation">;</span> <span class="token comment">// Error! Good - TypeScript protects us</span> <span class="token comment">// But wait, this works?</span> <span class="token keyword">let</span> obj<span class="token operator">:</span> object <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><span class="token punctuation">;</span> <span class="token punctuation">(</span>obj <span class="token keyword">as</span> <span class="token builtin">any</span><span class="token punctuation">)</span><span class="token punctuation">.</span>anything <span class="token operator">=</span> <span class="token string">"value"</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works (but you bypassed type safety!)</span> <span class="token comment">// Solution: Use exact types with a workaround</span> <span class="token keyword">type</span> <span class="token class-name">Exact<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">U</span> <span class="token keyword">extends</span> <span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token constant">U</span> <span class="token operator">&</span> Record<span class="token operator"><</span>Exclude<span class="token operator"><</span><span class="token keyword">keyof</span> <span class="token constant">U</span><span class="token punctuation">,</span> <span class="token keyword">keyof</span> <span class="token constant">T</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token builtin">never</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token keyword">type</span> <span class="token class-name">ExactUser</span> <span class="token operator">=</span> Exact<span class="token operator"><</span>User<span class="token punctuation">,</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 builtin">string</span> <span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// Error: Type '{ name: string; age: number; email: string; }' is not assignable to type 'ExactUser'</span> |
Pitfall 2: Optional Properties and Undefined
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="token keyword">interface</span> <span class="token class-name">Config</span> <span class="token punctuation">{</span> timeout<span class="token operator">?</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 keyword">let</span> config<span class="token operator">:</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">// These are different:</span> config<span class="token punctuation">.</span>timeout <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> <span class="token comment">// ✓ Works</span> config<span class="token punctuation">.</span>timeout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// Error! (with strictNullChecks)</span> <span class="token comment">// If you want null too:</span> <span class="token keyword">interface</span> <span class="token class-name">Config</span> <span class="token punctuation">{</span> timeout<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Pitfall 3: Index Signatures and Specific Properties
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span class="token comment">// This seems like it should work:</span> <span class="token keyword">interface</span> <span class="token class-name">Styles</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>property<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> color<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> fontSize<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">// Error! 'backgroundColor' is not guaranteed by index signature</span> backgroundColor<span class="token operator">?</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 comment">// Solution: Make index signature match all known types</span> <span class="token keyword">interface</span> <span class="token class-name">Styles</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>property<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> color<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> fontSize<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> backgroundColor<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Part 14: Best Practices Summary
-
Start with interfaces for object shapes, switch to type aliases when needed
-
Be explicit about optional properties with
?– don’t rely on| undefinedalone -
Use readonly for immutable properties – especially IDs, timestamps
-
Prefer discriminated unions over optional properties for mutually exclusive states
-
Use utility types (
Partial,Pick,Omit) to avoid duplication -
Keep objects focused – if it has more than 5-7 properties, consider splitting
-
Document complex object types with comments and examples
-
Use branded types for primitive-like values:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
<span class="token keyword">type</span> <span class="token class-name">UserId</span> <span class="token operator">=</span> <span class="token builtin">string</span> <span class="token operator">&</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> __brand<span class="token operator">:</span> unique <span class="token builtin">symbol</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">type</span> <span class="token class-name">OrderId</span> <span class="token operator">=</span> <span class="token builtin">string</span> <span class="token operator">&</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> __brand<span class="token operator">:</span> unique <span class="token builtin">symbol</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">createUserId</span><span class="token punctuation">(</span>id<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> UserId <span class="token punctuation">{</span> <span class="token keyword">return</span> id <span class="token keyword">as</span> UserId<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
The Big Picture
Object types in TypeScript are how we bring order to the flexibility of JavaScript objects. They transform chaos into clarity, turning:
-
Vague objects into precise models
-
“Maybe this has a name?” into “This definitely has a string name”
-
“I hope this function gets what it needs” into “This function requires exactly these properties”
Every time you define an object type, you’re creating a contract. You’re saying “This is what I promise to provide, and this is what I need from you.” That contract makes your code predictable, self-documenting, and most importantly – safe.
Remember: TypeScript object types aren’t just for the compiler. They’re for your teammates, your future self, and anyone else who reads your code. They’re the difference between “I think this is how it works” and “I KNOW this is how it works.”
Does this help clarify TypeScript object types? Would you like me to elaborate on any particular aspect or show more examples of advanced patterns?
