TypeScript
Completed
-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
16: Optional and Default Parameters
Imagine you're ordering a custom pizza. The shop needs to know what size you want—that's non-negotiable. But then there are the toppings. You might want extra olives, or you might not; it's totally optional. Finally, there's the crust. You can pick your own, but if you just say "give me a pepperoni pizza" and don't mention the crust, the shop doesn't just stop working—they have a standard "Hand-Tossed" crust they use by default.
In TypeScript, our functions work the same way. Not every piece of data is mandatory for a function to do its job, and sometimes it's cleaner to provide a "standard" value rather than forcing the caller to specify one every single time.
Handling the "Maybe" with Optional Parameters
When you mark a parameter as optional using the ? symbol, you're telling TypeScript: "Hey, this value might be here, or it might be undefined."
I've found that this is incredibly useful for configuration objects or user profiles where some data is just missing. Take a look at this function that formats a user's full name:
function formatUserName(firstName: string, lastName: string, middleName?: string) {
if (middleName) {
return `${firstName} ${middleName} ${lastName}`;
}
return `${firstName} ${lastName}`;
}
console.log(formatUserName("Jane", "Doe")); // "Jane Doe"
console.log(formatUserName("Jane", "Quinn", "Marie")); // "Jane Quinn Marie"
Notice that middleName? makes that argument optional. If I don't provide it, TypeScript doesn't throw a fit; it just treats it as undefined inside the function. Just remember: because it's optional, you must check if it exists before using it in a way that expects a string, otherwise you're just inviting undefined to crash your app.
Setting a Safety Net with Default Values
Optional parameters are great, but sometimes undefined is a pain to deal with. That's where default parameters come in. Instead of saying "this might be missing," you say "if this is missing, use this value instead."
Let's say we're building a function to fetch data from an API. We want to allow the user to specify a page number, but if they don't, we should just start them at page 1.
function fetchPosts(category: string, page: number = 1) {
console.log(`Fetching ${category} posts from page ${page}...`);
}
fetchPosts("typescript"); // "Fetching typescript posts from page 1..."
fetchPosts("javascript", 5); // "Fetching javascript posts from page 5..."
By assigning page = 1 in the signature, I've done two things at once. First, I've given the parameter a default value. Second, I've implicitly made it optional. I don't need the ? anymore because TypeScript knows that if the value isn't provided, it has a fallback.
The Order of Operations
Here is where I see people get tripped up most often: the order of your parameters matters. You can't put a required parameter after an optional or default one.
Think about it—if you have function doSomething(a?: string, b: string) and you call doSomething("Hello"), TypeScript has no way of knowing if "Hello" is meant for a or b. To keep things sane, always put your required parameters first, followed by your defaults or optionals.
📋 Practical Task
Build a Notification Dispatcher
You are building a notification system for an app. Create a function called sendNotification that takes the following parameters:
message: A required string.priority: A string that defaults to"low".recipientId: An optional string (since some notifications are global broadcasts).
The function should log a string to the console in this format:
"Sending [priority] priority message to [recipientId]: [message]"
If recipientId is not provided, replace it with the text "everyone" in the log.
Test your function with these three scenarios:
- A message with only the required
messageargument. - A message with a
messageand a specificpriority. - A message with all three arguments provided.
There are no comments for now.