0

I am trying to safely implement the following function

type OneOrAll<T extends any[]> =
    T extends { length: 1 } ? T[0] :
    T

interface Foo {
  // ...
}

declare function oneOrAll<A extends Foo[]>(...as: A): OneOrAll<A>;

which should either return Foo or Foo[] depending on the length of the given parameters. For example

const x: Foo = oneOrAll(fooA);
const xs: Foo[] = oneOrAll(fooA, fooB);

The types work out already, but I am struggling to write the implementation. My first attempt was this

function oneOrAll<A extends Foo[]>(...as: A): OneOrAll<A> {
    if (as.length == 1) {
        return as[0]; // Type 'Foo' is not assignable to type 'OneOrAll<A>'.
    }
    return as; // Type 'A' is not assignable to type 'OneOrAll<A>'.
               //   Type 'Foo[]' is not assignable to type 'OneOrAll<A>'.
}

however this does not compile with the inlined errors. What is the proper way to implement this function?

2
  • 1
    Unresolved conditional types (ie those that still contain type parameters) will often require type assertions. Don't think there is a way around it. You could use overloads instead Commented Jul 19, 2019 at 14:39
  • 2
    side note: using as as an identifier in TypeScript is unfortunate. Commented Jul 19, 2019 at 15:07

1 Answer 1

1

You can use function overriding to implement your function:

function oneOrAll<A extends [Foo]>(x: A[0]): A[0]
function oneOrAll<A extends Foo[]>(...xs: A): A
function oneOrAll<A extends Foo[]>(...xs: A): A[0] | A {
    if (xs.length === 1) {
        return xs[0]
    }
    return xs
}

You get the following result:

declare const foo: Foo
const x = oneOrAll(foo) // Foo
const y = oneOrAll(foo, foo) // [Foo, Foo]
Sign up to request clarification or add additional context in comments.

Comments

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.