Reputation: 960
I have the following function :
function demo<T>(init: T) {
return init;
}
I would like to give init
the default value {}
when omitted. So I wrote :
function demo2<T>(init: T = {}) {
return init;
}
But of course, this gives me the error :
Type '{}' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to '{}'.(2322)
How could I force T
to be {}
when the parameter is omitted ? Thank you.
Upvotes: 1
Views: 466
Reputation: 330086
The error is technically correct; the callers of your demo2()
function is allowed to specify the type parameter T
to be whatever they want it to be. This means a call like the following will not result in a compiler error, yet will easily lead to a runtime error:
const z2 = demo2<{ a: number }>(); // uh oh, no error
z2.a.toFixed(); // no error at compile time but "z2.a is undefined" at runtime
Still, if you think the likelihood of someone doing that (manually specifying a generic type parameter) is low, you can use a type assertion to suppress the error, while at the same time using a generic parameter default so that the compiler will infer {}
for T
when you leave out the init
property:
// assertion with default type parameter
function demo3<T = {}>(init: T = {} as T) {
return init;
}
This gives you the following desirable behavior:
const x3 = demo3(); // {}
const y3 = demo3({ a: 123 }); // {a: number}
while still allowing the following undesirable behavior:
const z3 = demo3<{ a: number }>(); // no compiler error
z3.a.toFixed(); // RUNTIME ERROR!
If you want to prohibit manually specifying T
without passing in a value of type T
, you might consider using something like an overloaded function with multiple call signatures:
// overload
function demo4(): {};
function demo4<T>(init: T): T;
function demo4(init = {}) {
return init;
}
Here, if a caller leaves out the init
parameter, the function is no longer treated as generic; the return type is just {}
. On the other hand, if the caller provides an init
parameter, then the function is treated just like your original demo()
function. The implementation of the function works for either call signature.
This also results in the desirable behavior for "normal" calls:
const x4 = demo4(); // {}
const y4 = demo4({ a: 123 }); // {a: number}
And also gives a compiler warning if someone tries to call it the wrong way:
const z4 = demo4<{ a: number }>(); // compiler error! an argument for init is required
Upvotes: 2