Sam Denty
Sam Denty

Reputation: 4085

Typescript conditional parameter union types

I'm attempting to create a function which accepts a fixed amount of typed parameters, but depending on the first parameter sequential parameter types are different.

So far, I haven't been able to find anything about this in the Typescript documentation.

Example:

function myFunc(name: 'one' | 'two', data?: 1 | 2) {
  //
}

// Okay
myFunc('one', 1)
myFunc('two', 2)
myFunc('two')

// Should throw an error
myFunc('one', 2)
myFunc('two', 'string')

Upvotes: 1

Views: 3092

Answers (2)

MrWolfZ
MrWolfZ

Reputation: 418

As jcalz mentioned in his answer you can in fact achieve this by using generics and the new conditional types feature that will be released with TypeScript 2.8.

If you are using an npm based project you can try it out locally by installing the latest nightly build like this (the -g can be left out if you want to only install it in a local project):

npm install -g typescript@next

The code would look like this:

// the parens around the conditional expression are optional
function myFunc<T1 extends 'one' | 'two', T2 extends (T1 extends 'one' ? 1 : 2)>(name: T1, data?: T2) {
  // do what you want
}

// No errors
myFunc('one', 1);
myFunc('two', 2);
myFunc('two');

// All of these cause a compile error
myFunc('one', 2);
myFunc('two', 1);
myFunc('three');
myFunc('two', 'string')
myFunc('one', 3);

// the first invocation (i.e. myFunc('one', 1)) leads to this resolved type
function myFunc<"one", 1>(name: "one", data?: 1 | undefined): void

Upvotes: 3

jcalz
jcalz

Reputation: 328262

You probably want to overload the function signature:

function myFunc(name: 'one', data?: 1);
function myFunc(name: 'two', data?: 2);
function myFunc(name: 'one' | 'two', data?: 1 | 2) {
  //
}

// Okay
myFunc('one', 1)
myFunc('two', 2)
myFunc('two')

// Does throw an error
myFunc('one', 2)
myFunc('two', 'string')

There's probably also a way to do this with a generic function, but overloads are the most straightforward way to do what you're after. I really recommend reading the useful and accessible TypeScript handbook for insight into stuff like this.

Hope that helps; good luck!

Upvotes: 5

Related Questions