0

Description

I would like like to define a Generic function in TypeScript so that it would apply a transformation to the array argument and then return an array of same type. (TypeScript version used: v3.24)

Simplified code snippet as follow:

describe("generic functions", function () {
    it("should not give transpilation error", function () {
        // given
        function myFunction<T>(arr: T[]): T[] {
            // ...... apply some transformation to the array here
            return arr; // or return a copy of the array of same type
        }

        let arrays = [
            ["a"],
            [1]
        ]; // Just for demonstration purpose, the actual input has more varieties of types

        // These can be transpiled without error
        myFunction(["b"]);
        myFunction([2]);
        arrays.map(myFunction);

        // This gives transpilation error, see following for the detailed message
        arrays.map(arr => myFunction(arr));
    });
});

In particular I am not sure why the TS compiler would fail to recognize the type only when I am applying the function to an array of mixed type and calling it explicitly.

The transpilation error message is:

TS2345: Argument of type 'string[]| number[]' is not assignable to parameter of type 'string[]'. Type 'number[]' is not assignable to type 'string[]'. Type 'number' is not assignable to type 'string'.

Similar question

  1. Assigning generics function to delegate in Typescript - But I would like to keep the generic signature as I want my function to be more flexible
  2. Typescript Generic type not assignable error - But my function is returning the generic type.

(Apologies and please let me know if this duplicates with another question - I had tried to search but failed to find question that could answer this)

1 Answer 1

1

The compiler is having trouble unwrapping the (string[] | number[]) type to infer the type argument. In this case, explicitly passing the type argument will work:

arrays.map(arr => myFunction<string | number>(arr));

This is one of those cases where the compiler treats:

(string | number)[][]

Differently to:

(string[] | number[])[]

If you use the latter, it infers the type argument as string[], which then fails for number[].

You can help the compiler with a type guard, but this example is really thought exercise and I can't imagine wanting to use this in real life:

function isStringArray(arr: any[]): arr is string[] {
    return (typeof arr[0] === 'string');
}

arrays.map(arr => (isStringArray(arr)) ? myFunction(arr) : myFunction(arr));

Even though it calls myFunction either way, it can infer the type argument as string[] and number[] in each case.

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.