2

I'm trying to learn more about conditional types in TS and, as a small challenge, decided to write something like a generic mapper. But I have stuck with an error

What I need to do:

  • into createMapper function need to pass a mapper;
  • from createMapper return a function which input property can receive a value or an array of values;
  • after passing a value ts compiler must explicitly understand what type is returned from a function;

something like:

type MapI = { abc: 123 };
const mapI: MapI = { abc: 123 };

const mappedArray = mapps<MapI, MapI>((m) => m)(Array(3).fill(mapI));
console.log(mappedArray.length); // no errors, compiler understands that it is an array;

const mappedValue = mapps<MapI, MapI>((m) => m)(mapI);
console.log(mappedValue.abc); // no errors, compiler understands that it is an object;

Here is a code of this function, it can be a little bit ugly, but it's only the first implementation of this function:

function createMapper<In, Out>(
    mapper: (input: In) => Out
): <Source extends In | In[]>(source: Source) => Source extends In[] ? Out[] : Out {
    return (source) => Array.isArray(source)
        ? source.map(mapper)
        : mapper(source);
}

And I have no errors in type recognition by ts compiler but I have an error in function implementation.


Type 'Out | Out[]' is not assignable to type 'Source extends In[] ? Out[] : Out'.
  Type 'Out' is not assignable to type 'Source extends In[] ? Out[] : Out'

This function is available in the playground:

https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABBATgUwIZTQWQwB3zRQB4BJMAGkQHkQoA+ACgChF3EBbAolALkRMYYfPQEUAlIgC8DWvRYSBJAMpwQKCGkRoAHtjAATAM6IKiAD5mwAbQC6zY+s1oBajVqmzE7lzv1oRqYU9ogA-PJQoQJ0UIgA3mwc6FAaSExOHmhecgCCKCgYAJ4AdDDG+YVFGc6eSRwcEZkuJdz4TG28EvUNiAKdxDVZEgDcLAC+SSxQRUSIePhkMgmIGABGEAIAjABMAMyI42MQCMZxbWQCC0vSK+ubiLsHRywsJ2BnXDxohpXFy6hMNgFrwSNdqNdmB0clwJEw-tU9hISsAYAAbNEdAhkCSjN6nOBotAlNFwADmWMIPwRJMCZKgAAtRogAPQsxBgOA6ApwFDGagnTj4dHERDgQzEM4YIKIRlYRAwOLlVZIDAFYpjfEfc7fQwANQwaJA2lugKwuG+pHB82xUM4MPtlJxxwJRJJ5MpRH1huNJXuzLZHK5xBQvP5yDgQpFKDFRklUGlJllDPlioVpmliDgawAVmhoCMgA

Can anyone, please, explain why this error happening and maybe the method to fix it.

Thank you and have a nice day!

1 Answer 1

1

Only function overloading in such cases:


function createMapper<In, Out>(
    mapper: (input: In) => Out
) {
    function condition<Source extends In | In[]>(source: Source): Source extends In[] ? Out[] : Out
    function condition(source: In | In[]) {
        return Array.isArray(source)
            ? source.map(mapper)
            : mapper(source);
    }

    return condition
}

type MapI = { abc: 123 };
const mapI: MapI = { abc: 123 };

const mappedArray = createMapper<MapI, MapI>((m) => m)(Array(3).fill(mapI)); // MapI[]


const mappedValue = createMapper<MapI, MapI>((m) => m)(mapI); // MapI

Playground

COnsitional types in a place of return type does not supported by TS

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

2 Comments

Hi, I've tried to make it with overload and yep it works fine. I just thought that it is any way to do it without :) Thank you, for your answer!
@IamCracker there are two ways: overliading or type assertion.

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.