Home > Software engineering >  How to make one type depends on argument
How to make one type depends on argument

Time:12-22

Is it possible to make return type of function dependent on the argument type?

const exampleFunction<T> = (initial?: T, ...anotherArgs) => { ...Some logic }

In this example by default we can use T | undefined, but I need that return type of function always be T if initial data is defined and (T | undefined) if it is undefined

CodePudding user response:

Is it possible to make return type of function dependent on the argument type?

This question in a general sense is typically answered by function overloads.

In this case you could do something like:

function exampleFunction<T>(initial: T): T // overload 1
function exampleFunction(initial?: undefined): undefined // overload 2

// Implementation
function exampleFunction<T>(initial?: T): T | undefined {
    return initial
}

const a: { abc: number } = exampleFunction({ abc: 123 }) // use overload 1

const b: undefined = exampleFunction() // use overload 2
const c: undefined = exampleFunction(undefined) // use overload 2

Playground


However, reading your question more carefully...

always be T if initial data is defined and (T | undefined) if it is undefined

You can change the second overload to:

function exampleFunction<T>(initial?: undefined): T | undefined // overload 2

But that will require a manual type for T since none can be inferred.

const b: { def: string } | undefined = exampleFunction<{ def: string }>() // use overload 2

Playground

CodePudding user response:

You can use a function which simply extracts the first element type from rest parameters.

  • If no arguments are provided, the return type will be undefined because the first argument's type is (implicitly) undefined
  • If the first argument is T | undefined, so will be the return type
  • If the first argument type is T, so will be the return type

TS Playground

function typeOfFirstArgument <Args extends readonly any[]>(...args: Args): Args[0] {
  const [first] = args;
  // ...
  return first;
}

const result1 = typeOfFirstArgument(); // undefined
const result2 = typeOfFirstArgument('ok', 'another'); // string
const result3 = typeOfFirstArgument(...['ok', 'another'] as const); // "ok"
const result4 = typeOfFirstArgument({ msg: 'hello world' }, ['foo', 'bar']); // { msg: string }

let value: string | undefined;
const result5 = typeOfFirstArgument(value); // string | undefined
  • Related