Rafal Lesniak
Rafal Lesniak

Reputation: 556

Make last argument conditionally optional typescript

I want to make last arg of function conditionally optional, eg. if previous argument has type null, make last optionial (?), if previous has value, make last arg required.

Is this possible?

Playground here: https://typescript-play.js.org/#code/MYewdgzgLgBAZgVzMGBeGAeAKgRgDQxYBMAfABQAOAhgE5UC2OAXIfjNXfUS7jAKYAPKHzAATCDDAIANtJgB+SXwBufGjxwBKNCRgBvAL4BuAFAmA9OZgALNXxg0+ARwQBLRzFoBzE4mRkAcilZAM1TCytbRwIwEFhHF3d7Yl8kYDJg6TCTIA

Upvotes: 0

Views: 129

Answers (2)

jcalz
jcalz

Reputation: 330116

You could use a union of rest tuples to give you this behavior:

const func = (...param: [null, unknown?] | [unknown, unknown]) => {};

func("a", "b"); // okay
func("a"); // error!  Type 'string' is not assignable to type 'null'.
func(null); // okay
func(null, "b"); // okay

Or, you could use the traditional (pre-TS3.0) solution to this, overloads:

const func: {
  (param1: null, param2?: unknown): void; // first call signature
  (param1: unknown, param2: unknown): void; // second call signature
} = (param1: unknown, param2?: unknown) => {};

func("a", "b"); // okay
func("a"); // error!  Type '"a"' is not assignable to parameter of type 'null'.
func(null); // okay
func(null, "b"); // okay

Either of those should work for you. Hope that helps; good luck!

Link to code

Upvotes: 1

VLAZ
VLAZ

Reputation: 29093

I think this is better expressed as two mutually exclusive parameter objects. You can define two (or more) types that your function expects.

  • One will only have a single value and that value would be null. For ease, I will also make the value optional:
interface SingleParamObject {
    param1?: null
}
  • The next type has two parameters and mandates that the first one is not null:
interface TwoParamObject<T1, T2> {
    param1: NonNullable<T1>,
    param2: T2
}

This is a bit more typing for this case, at least but I think it addresses the problem more comprehensively - you either want to pass a parameter object with param1 either missing or null or you want both param1 and param2:

const func = <T1, T2>(params: SingleParamObject|TwoParamObject<T1, T2>) => {};

This makes it more expressive what you want to do and you can also add more shapes for parameter objects - perhaps you want nothing, or param1 + param2, or param1 + param2 + param3 + param4, or whatever combinations you want.

Check on TypeScript Playground

Upvotes: 0

Related Questions