I was able to generate a union of 55 tuples with maximum length - 110 elements.
It means tuples with next length:
110 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | ... 13 more ... | 108
There is a limit up to 110 elements in the tuple
type MathCall = [
    '+' | '-' | '/' | '*' | '>' | '<',
    Expression,
    Expression,
];
type Expression = number | string | boolean | MathCall;
type CallParams = [Expression, Expression]
/**
 * It is not allowed to increase this number, at least in TS.4.4
 */
type MAXIMUM_ALLOWED_BOUNDARY = 110
type Mapped<
    Arr extends Array<unknown>,
    Result extends Array<unknown> = [],
    Original extends any[] = [],
    Count extends ReadonlyArray<number> = []
    > =
    (Count['length'] extends MAXIMUM_ALLOWED_BOUNDARY
        ? Result
        : (Arr extends []
            ? []
            : (Arr extends [infer H]
                ? [...Result, H, ...([] | Mapped<Original, [], [], [...Count, 1]>)]
                : (Arr extends [infer Head, ...infer Tail]
                    ? Mapped<[...Tail], [...Result, Head], Arr, [...Count, 1]>
                    : Readonly<Result>
                    )
            )
        )
    )
// Main result
type CaseCallParams = Mapped<CallParams>
// TESTS
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
    k: infer I
) => void
    ? I
    : never;
// credits goes to https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468114901
type UnionToOvlds<U> = UnionToIntersection<
    U extends any ? (f: U) => void : never
>;
type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
    ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
    : [T, ...A];
type Result = UnionToArray<CaseCallParams>[3]['length']; // 8
type Result_ = UnionToArray<CaseCallParams>[4]['length']; // 10
type Result__ = UnionToArray<CaseCallParams>[10]['length']; // 12
type Result___ = UnionToArray<CaseCallParams>[12]['length']; // 26
type Result____ = UnionToArray<CaseCallParams>[20]['length']; // 42
type Result_____ = UnionToArray<CaseCallParams>[50]['length']; // 102
type Result______ = UnionToArray<CaseCallParams>[54]['length']; // 110
// should end with 0 , 2 , 4 , 6 , 8
type EvenNumbers = UnionToArray<CaseCallParams>[number]['length']
Please let me know if it works for you.
Playground
I think it will be possible to increase the limit after Tail recursive evaluation of conditional types will be merged
ALso , you can define a function which will validate the length of the tuple:
type EvenEnd = '0' | '2' | '4' | '6' | '8'
type IsEven<T extends `${number}`> =
    (T extends `${infer Int}${infer Rest}`
        ? (
            Rest extends ''
            ? (Int extends EvenEnd
                ? true
                : false
            )
            : (Rest extends `${number}`
                ? IsEven<Rest>
                : false
            )
        )
        : false
    )
{
    type Test1 = IsEven<'80'> // true
    type Test2 = IsEven<'9010'> // true
    type Test3 = IsEven<'1'> // false
    type Test4 = IsEven<'99999999'> // false
}
type EvenLength<T extends Expression[]> =
    IsEven<`${T['length']}`> extends true
    ? T
    : never
const evenTuple = <
    T extends Expression,
    Tuple extends T[]
>(tuple: EvenLength<[...Tuple]>) => tuple
evenTuple([1, 3]) // ok
evenTuple([1, 3, 4]) // error
Playground 2
My article
UPDATE
Another one solution, which allows you to create a tuple with 999 elements.
type Expression = number | string | boolean | CallExpression;
type CallExpression = MathCall | CaseCall;
type MathCall = [
    '+' | '-' | '/' | '*' | '>' | '<',
    Expression,
    Expression,
];
type MAXIMUM_ALLOWED_BOUNDARY = 999
type Mapped<
    N extends number,
    Result extends Array<unknown> = [],
    > =
    (Result['length'] extends N
        ? Result
        : Mapped<N, [...Result, Result['length']]>
    )
// 0 , 1, 2 ... 998
type NumberRange = Mapped<MAXIMUM_ALLOWED_BOUNDARY>[number]
type Dictionary = {
    [Prop in NumberRange as `${Prop}`]: Prop
}
type EvenEnd = '0' | '2' | '4' | '6' | '8'
type IsEven<T extends `${number}`> =
    (T extends `${infer Int}${infer Rest}`
        ? (
            Rest extends ''
            ? (Int extends EvenEnd
                ? true
                : false
            )
            : (Rest extends `${number}`
                ? IsEven<Rest>
                : false
            )
        )
        : false
    )
type Compare<Num extends number> =
    Num extends number
    ? IsEven<`${Num}`> extends true
    ? Num
    : never
    : never
type EvenRange = Exclude<Compare<NumberRange>, 0>
type CaseCall<Exp = any> = {
    [Prop in Exclude<NumberRange, 0>]?: Exp
} & { length: EvenRange }
const tuple: CaseCall<Expression> = [1, 1, 1, 1] as const // ok
const tuple2: CaseCall<Expression> = [1, 1, 1] as const // expected error
const handle = <
    Exp extends Expression, Data extends Exp[]
>(
    arg: [...Data],
    ...check: [...Data]['length'] extends EvenRange ? [] : [never]
) => arg
handle([1, 1, 1]) // expected error
handle([1, 1]) // ok
Playground
UPDATE 2
Easier approach to create union of tuples with even length:
type MAXIMUM_ALLOWED_BOUNDARY = 50
type Mapped<
    Tuple extends Array<unknown>,
    Result extends Array<unknown> = [],
    Count extends ReadonlyArray<number> = []
    > =
    (Count['length'] extends MAXIMUM_ALLOWED_BOUNDARY
        ? Result
        : (Tuple extends []
            ? []
            : (Result extends []
                ? Mapped<Tuple, Tuple, [...Count, 1]>
                : Mapped<Tuple, Result | [...Result, ...Tuple], [...Count, 1]>)
        )
    )
type Result = Mapped<[string, number]>
// 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24
type Test = Result['length']
Playground