2

I'm trying to create a type for array's functions in a way that it can return different type depending on wether input array is empty or not.

I tried to use conditional type in combination with tuples

First try:

export const lastElement = <T, U extends T[]>(array: U): U extends [T, ...T[]] ? T : null => {
  return array[array.length - 1]
}

The code above returns the following error:

Type 'T' is not assignable to type 'U extends [T, ...T[]] ? T : null'.ts(2322)

array.ts(343, 29): This type parameter might need an extends U extends [T, ...T[]] ? T : null constraint.

It looks like for some reason TS doesn't try to check condition and just assign return type to the whole expression

Second try:

export const lastElement = <T, A extends T | null, U extends [A, ...T[]]>(array: U): A extends null ? null : T => {
  return array[array.length - 1]
}

The code above returns the following error:

Type 'T | A' is not assignable to type 'A extends null ? null : T'.
Type 'T' is not assignable to type 'A extends null ? null : T'.

Again it looks like the TS doesn't understand that there is a condition in return type

Question

Is it possible to use condition types on typles in type script? Is there a way to make a condition on an element of a tuple?

2
  • Why are you returning null when it's supposed to be undefined Commented Nov 17, 2022 at 16:01
  • The result is the same with undefined. For the subject it basically doesn't matter. Commented Dec 8, 2022 at 8:10

1 Answer 1

2

I am not really sure why you tried to have two or even three generic types. There is only one parameter. So one generic type should be enough.

Having multiple generic types messed up your inference in both examples. So let's just have a single generic type T which has to be an array. Let's also use the variadic tuple syntax to let TypeScript infer T as a tuple instead of an array.

export const lastElement = <
  T extends any[]
>(array: [...T]): T extends [...any[], infer U] ? U : null => {
  return array[array.length - 1]
}

In the conditional, we infer the last element of T and return it if it exists.

lastElement([]) // null
lastElement(["abc", new Date(), 3]) // number

Playground

Sign up to request clarification or add additional context in comments.

4 Comments

Maybe the explanation wasn't clear. What I want to be able to verify the output type of the lastElement function. So if I pass a non empty array to it ts won't complain that result of lastElement can be null. With you implementation it doesn't work. ``` const test = ['test'] lastElement(test).toLowerCase() ``` Complains that result of lastElement can be null, although the test array is not empty
In other words I want a type definition for function that will return different type depending on argument. If argument type is [T, ...T[]], then result type is T, otherwise it's null
The type of the variable test is inferred to be string[]. It contains no information about about the number of elements inside and it could just as well be empty. You have to use tuple types. Otherwise TypeScript has no clue if an array might be empty or not.
Yep, this is why I used tuples keyword in the question subject

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.