简体   繁体   中英

Typescript: express optional parameter in generic

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM