Apparently in typescript there's a difference between optional parameter and parameter of union type with undefined
function test(s: string|undefined) {}
function test2(s?: string) {}
test() // error: An argument for 's' was not provided
test2() // OK
I want to declare a generic function that depending on the provided type would have its parameter optional or required. For example:
// Intention: if type is the same as its Partial counterpart then the parameter can be made optional
type MaybeOptional<T> = Partial<T> extends T ? T|undefined : T
type O = {
name?: string
}
function generic<T extends any>(t: MaybeOptional<T>) {}
generic<O>({name:""})
generic<O>() // error. An argument for 't' was not provided.
How can I express such intention in Typescript? Can I assign this 'optional' trait through generics?
You could use tuples in rest/spread positions to talk about a function's argument list in a more flexible way:
function generic<T extends any>(...args: Partial<T> extends T ? [t?: T] : [t: T]) { }
If, when you call generic<T>(), the type T is all-optional and Partial<T> extends T, this reduces to (...args: [t?: T]) => void, meaning "a list of arguments whose length is one and whose one element is optional and of type T", which reduces to (t?: T) => void). If, on the other hand, the type T is not all-optional, then this reduces to (...args: [t: T])=>void; the same as before except the element is required, which reduces to (t: T) => void.
Let's test it:
type O = {
name?: string
}
generic<O>({ name: "" }); // okay
generic<O>({}); // okay
generic<O>(); // okay
type R = {
name: string;
}
generic<R>({ name: "" }); // okay
generic<R>({}); // error
generic<R>(); // error
Looks good!
Playground link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With