Repository navigation
required function parameters with default valuesΒ #47202
Description
Suggestion
π Search Terms
required parameter default value non-optional function
β Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
β Suggestion
It should be possible to mark a function parameter with a default value as required, so that it can't be undefined.
π Motivating Example
Consider the following function:
function printHelloWorld(printer = defaultPrinter){
printer.print("hello world!")
}It's clear that it needs a printer to work. But in this form, TypeScript would allow the following call to the function:
printHelloWorld(undefined)Which is also why it would complain that printer is possibly undefined in strict mode. Even when the type of the parameter is explicitly defined, it can still be undefined when it has a default value. This is because an argument being optional is tightly coupled with it having a default value.
But just because an argument has a default value, it shouldn't mean that it can be undefined. It should just mean, that it's automatically assigned, if it's not provided in the function call.
In a perfect world, I'd propose to make this the default behavior, and add a feature to mark arguments that are truly optional with a "?" after the name. But since that would break existing code, I propose the opposite: Marking required properties with a "!".
Example:
function printHelloWorld(printer! = defaultPrinter){
printer.print("hello world!")
}
printHelloWorld(undefined) // this should not compileπ» Use Cases
I like to make function dependencies overridable by optional parameters that default to the main implementation, like in the example above, or grouped to an object like this:
function someComplexFunction(arg1: number, arg2: string, dependencies! = {dependency1,dependency2}){
dependency1.foo(arg1);
dependency2.bar(arg2);
}This makes the function unit testable in a very easy way, and doesn't need a dependency injection framework for the real application.
But this currently only works with strictNullChecks turned off, because otherwise typescript would complain that the dependencies could be undefined.
Activity
MartinJohns commentedon Dec 20, 2021
This sounds like a duplicate of #44548. At least your issue would be solved by #44548.
fatcerberus commentedon Dec 20, 2021
For the record, a parameter with a default value can't be
undefinedinside the function:VanCoding commentedon Dec 20, 2021
Bruce Pascoe (@fatcerberus) wow, I didn't realize that. That makes it even more obvious that we need to change something! Probably even without new syntax.
fatcerberus commentedon Dec 20, 2021
Patrik Stutz (@VanCoding) Itβs actually useful because it lets you omit arguments in the middle of a call if they have default values while still providing explicit values for later ones. If it were an error to pass
undefined, that wouldnβt be possible.VanCoding commentedon Dec 20, 2021
oooohhh! Now I understand, the type is different inside the function from outside the function. Yes, this makes sense!
I only now realise that my initial example would compile, because inside the function the printer cannot be undefined.
So my use cases are already supported o.o
I think what initially led me to believe that there's a problem is that
Parameters<typeof myfunction>always gave me a union with undefined for those arguments. But that's of course, because it's looked at from outside the function and can easily be worked around usingExclude<Parameters<typeof myfunction>[0],undefined>We can close this now. Thanks guys!
Maverick283 commentedon Jun 5, 2023
Well strictly speaking it can be undefined, right?
Nevertheless, going back to the original point that Patrik Stutz (@VanCoding) made, what can one do in strict mode for default values of parameters?
Say I have the following code
then this would result in a compiler error like
And it was made clear that y is always going to be a number because of either the type of
Foo['y']or the type of the default value as fallback.So why is this an error?
PS: Sorry if I should have opened a new issue or put this anywhere else, I am new here!
MartinJohns commentedon Jun 5, 2023
It would not. It works just fine.