Best Practices Generics in Typescript I'm wondering and actually playing in typescript playground with generics functions. The question is, is the code below readable? If not what kind of approach I could use to make it more typescript way and more readable?
Working example here
I implemented some basic functions like foldl, map and filter to experiment generics, maybe the implementation don't satisfies all requirements in the sense of functionality.
type FoldlFunction&lt;T&gt; = (a: T, b: T) =&gt; T;

function Foldl&lt;T&gt;(f: FoldlFunction&lt;T&gt;, base: T, arr: T[]): T {
    const [head, ...rest] = arr;
    return !head ? base : Foldl(f, f(base, head), rest);
}

console.log(Foldl((a: number, b: number) =&gt; (a + b), 0, [1,2,3,4,12,14,15,16]));

type MMapFunction&lt;T,R&gt; = (a: T) =&gt; R;

function MMap&lt;T,R&gt;(f: MMapFunction&lt;T,R&gt;, arr: T[]): R[] {
    const [head, ...rest] = arr;
    return !head ? [] : [f(head), ...MMap(f, rest)];
}

console.log(MMap((x: number) =&gt; (x * x), [1,2,3,4,12,14,15,16]));

type FilterFunction&lt;T&gt; = (a: T) =&gt; boolean;

function Filter&lt;T&gt;(f: FilterFunction&lt;T&gt;, arr: T[]): T[] {
    const [head, ...rest] = arr;
    return !head ? [] : 
        (f(head) ? [head, ...Filter(f, rest)] : [...Filter(f, rest)])
}

console.log(Filter((x: number) =&gt; (x % 2 === 0), [1,2,3,4,12,14,15,16]));
Your code looks quite reasonable, though there are a few tweaks you could consider.
Function or Callback? Rather than names like FoldlFunction and MMapFunction, since what those types contain are the types for the callback run for each element of the array, consider calling them FoldlCallback etc instead. It's a bit more precise and will make more intuitive sense at a glance. (One might think at a glance that FoldlFunction might refer to the type of the whole Foldl function, which is incorrect.)
camelCase is the near-universal convention for plain non-class functions and variables in JavaScript. PascalCase is generally used for class constructors and namespaces, which aren't being used here, so camelCase is probably more appropriate. Eg Foldl -&gt; foldl (or to foldL).
DRYer types You only need to specify the type of a parameter when TypeScript can't infer it automatically. For example, with foldl, since the base value is T, and the array is T[], the callback - the f: FoldlFunction&lt;T&gt; - will be known to be of the form (a: T, b: T) =&gt; T. There's no need to additionally specify the arguments' types when calling foldl. That is, this:
foldl((a: number, b: number) =&gt; (a + b), 0, [1,2,3,4,12,14,15,16])

can be
foldl((a, b) =&gt; (a + b), 0, [1,2,3,4,12,14,15,16])

It's a good idea to let TypeScript automatically infer the types of variables and parameters whenever possible - less code to read makes comprehension easier. You can do the same thing for MMap and Filter.
Outside definition? I'm not entirely convinced of defining the type of the function/callback outside - it's one more type parameter that needs to be cognitively pieced together. Consider defining the callback type in the parameter list:
function foldl&lt;T&gt;(
    f: (a: T, b: T) =&gt; T,
    base: T,
    arr: T[]
): T {
    const [head, ...rest] = arr;
    return !head ? base : foldl(f, f(base, head), rest);
}

console.log(foldl((a, b) =&gt; (a + b), 0, [1,2,3,4,12,14,15,16]));

I consider that significantly more readable. You can do the same thing for MMap and Filter.
Falsey bug You use return !head ? base : foldl.... This will not run if head is falsey. For example, foldl((a, b) =&gt; (a + b), 0, [1,2,3,4,12,14,15,16]) results in 67, but foldl((a, b) =&gt; (a + b), 0, [0, 1,2,3,4,12,14,15,16]) results in 0, which probably isn't desirable. Check the array's length instead:
function foldl&lt;T&gt;(
    f: (a: T, b: T) =&gt; T,
    base: T,
    arr: T[]
): T {
    if (!arr.length) {
        return base;
    }
    const [head, ...rest] = arr;
    return foldl(f, f(base, head), rest);
}

This applies to MMap and Filter as well.
DRYer filter To fix the falsey bug and make Filter a bit cleaner, you can replace:
const [head, ...rest] = arr;
return !head ? [] : 
    (f(head) ? [head, ...Filter(f, rest)] : [...Filter(f, rest)])

with
if (!arr.length) {
  return [];
}
const includeThis = f(head); // call this here to preserve callback execution order
const restFiltered = Filter(f, rest);
return includeThis ? [head, ...restFiltered] : restFiltered;