Когда компилятор видит литерал гетерогенного массива, он использует некоторую эвристику, чтобы определить, синтезировать ли объединение для типа элемента или выдать ошибку в первом элементе, который не соответствует предполагаемому типу. Это компромисс, потому что иногда вы хотите такую ошибку. Например, следующая ошибка обычно считается желательной, как упоминалось в связанном вопросе :
function same<T>(x: T, y: T) { };
same(0, ""); // error!
// ---> ~~
// argument of type "" is not assignable to number
Эта функция может быть превращена в пример массива, подобный этому:
function sameTuple<T>(x: [T, T]) { };
sameTuple([0, ""]); // error!
// ---------> ~~
// Type 'string' is not assignable to type 'number'.
И вы можете видеть дилемму ... иногда люди хотят, чтобы T
был союзом, в других случаях люди хотят ограничить вызовы однородными массивами.
В этом случае я 'Я бы предложил изменить тип fns
на что-то, для чего компилятор может предложить более широкий универсальный тип. Например:
function getX<F extends Array<() => any>>(fns: F, returns: ReturnType<F[number]>) {
const c: C<F[number], ReturnType<F[number]>> = {
fns,
returns,
};
return c;
}
Здесь универсальный тип F
должен быть любым, совпадающим с массивом функций без аргументов. Это самая простая вещь, которую можно вывести из типа fns
. Как только это удастся, вы можете синтезировать свой собственный тип для returns
как ReturnType<F[number]>
.
Теперь все должно работать так, как вы ожидаете, я думаю:
getX([b, a], "somen"); // okay
getX([b, a], "true"); // error!
// --------> ~~~~~~
// "true" is not assignable to true | "somen".
Хорошо, надеюсь, это поможет;удачи!
Ссылка на код