Тип соединения для generi c param - PullRequest
1 голос
/ 26 мая 2020

прокси возвращает условный случайный тип.

const numbersArray = [1,2,3,4];
const stringsArray = ['1','2','3','4'];


function func<T>(array: T[]): T[][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

const proxy = () => Math.random() < 0.5 ? numbersArray : stringsArray;

const resulNumbers = func(numbersArray);

const resultStrings = func(stringsArray);

const resultUnion = func(proxy()); // error

ошибка

const proxy: () => number[] | string[]

Argument of type 'number[] | string[]' is not assignable to parameter of type 'number[]'.
  Type 'string[]' is not assignable to type 'number[]'.
    Type 'string' is not assignable to type 'number'.(2345)

ссылка на игровую площадку

Как решить эту проблему, есть идеи?

Ответы [ 3 ]

1 голос
/ 26 мая 2020

Эта функция:

const proxy = () => Math.random() < 0.5 ? numbersArray : stringsArray;

имеет тип возвращаемого значения:

number[] | string[]

Этот тип говорит, что у вас есть либо массив всех чисел, либо массив всех строк , но никогда не смешивать и то, и другое.

Итак, каков тип членов этого типа? Вы можете подумать, что это number | string, но это не совсем правда. Если вы возьмете string | number и добавите обозначение массива в конец, вы получите:

(number | string)[]

Этот тип говорит, что это массив строк или чисел, и каждый член может быть любым из них. Теперь вы можете смешать оба. Это не одно и то же. Это означает, что тип члена не может быть выведен, потому что этот тип члена не может использоваться для создания исходного типа массива.

Теперь давайте посмотрим на общую c функцию:

function func<T>(array: T[]): T[][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

Эта функция пытается найти тип элемента T для массива T[]. Но, как показано выше, для string[] | number[] нет подходящего типа члена. Таким образом, машинописный текст не может вывести T и выдает ошибку.

Итак, чтобы ваша функция работала, тип члена T должен быть выводимым. Вы можете сделать это, преобразовав возвращаемый тип прокси в совместимый тип массива, в котором только члены массива являются объединением.

const proxy: () => (string | number)[] =
  () => Math.random() < 0.5 ? numbersArray : stringsArray;

Теперь T может стать string | number, и все работает так же, как вы ожидаем.

const resultUnion = func(proxy()); // type: (string | number)[][]

Детская площадка

0 голосов
/ 27 мая 2020

Ответ на вопрос, который здесь дублирует , объясняет, почему TypeScript не всегда выводит объединения для общих c параметров типа; это потому, что это часто указывает на ошибку, когда вызывающие абоненты указывают несколько вещей для одного параметра типа generi c, и если компилятор всегда выводил объединение в таких ситуациях, он допускал бы много, вероятно, неправильного кода. См. microsoft / TypeScript # 19656 для "официального" обсуждения этого.

В любом случае в вашем случае я бы, вероятно, изменил подпись func() на такую:

function func<T extends any[]>(array: T): T[number][][] {
  return [[array[0], array[1]], [array[2], array[3]]];
}

, и в этом случае T на самом деле является типом переданного массива, а не его членов, т.е. T[number]. Я думаю, это должно сработать для вас.

Надеюсь, это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 26 мая 2020

Ошибка возникает из-за того, как аргумент типа T разрешается для этого вызова func. Тип возврата proxy -

number[] | string[]

, а тип T определяется на основе того, как number[] | string[] вписывается в следующую сигнатуру:

function func<T>(x: T[]): T[][]

Итак x должен быть массивом T s, который может быть любого типа, насколько это касается func. В случае number[] | string[] предполагается, что тип T будет number, потому что number[] - это первый тип в объединении, который соответствует T[] для x. К сожалению, string[] не учитывается.

Возможно, вы захотите, чтобы T было number | string для этого вызова, и вы можете сделать это, явно указав типы при вызове func:

const xs: (number | string)[][] = func<number | string>(proxy())
...