Тип пересечения вложенного массива

#typescript #typescript-typings

#typescript #typescript-типизации

Вопрос:

Хотя пересечение типов отлично работает для такого примера:

 type Merged = (
    { lorems: { foo: string }[] } amp;
    { lorems: { bar: string }[] }
);

const x: Merged;

x.lorems[0].foo; // ok
x.lorems[0].bar; // ok
 

Но ни один из методов массива не поддерживает пересечение типов, например:

 x.lorems.shift().foo; // ok
x.lorems.shift().bar; // doesn't exist???
 

Но с таким взломом это работает:

 (x.lorems.shift() as typeof x.lorems[0]).bar;
 

Есть ли какой-нибудь способ создать объединенный тип с пересечениями вложенных массивов?

Комментарии:

1. Попробуйте сделать пересечение только для foo и bar

2. @captain-yossarian Оба типа в intersection являются сторонними типами, поэтому мы не можем изменять типы массивов.

Ответ №1:

Я считаю, что вам нужен тип объединения и защита типа какой-либо формы.

Если объект может быть одним из нескольких разных типов, для обеспечения безопасности типов. TS должен иметь возможность каким-то образом различать, относится ли что-то к типу или нет.

 
interface Type1 { shared: string; lorems: { foo: string }[] };
interface Type2 { shared: string; lorems: { bar: number }[] };
type TypeUnion = Type1 | Type2;

function getLorems(x: TypeUnion) {
  const t = x.lorems.shift();
  x.shared; // This is ok
  if ("foo" in t) t.foo;
  if ("bar" in t) t.bar;
}
 

Комментарии:

1. Объединение логически неверно. Поскольку тип (или объект) всегда содержит оба свойства. Вот почему наличие всех этих условий в коде не требуется.

2. @tenbits Я не знаю варианта использования, поэтому я предполагаю. Но если объект, который вы ожидаете, всегда имеет оба свойства, почему сторонние интерфейсы разделены на две модели? Это неправильный ввод. Подумайте об этом. Как вы можете сказать, что свойство объекта одновременно является «одной вещью» и «другой вещью» одновременно? Вы объединяете два разных типа вместе, которые не выглядят одинаково. Подобно тому, как сказать, что my array также является string … против my array или a string .

3. Это модели данных, а не что-то, поддерживаемое классами. Я использую несколько потоков данных и объединяю их в один объект данных. Но не путем мелкого слияния, а глубокого слияния.

4. Также следует отметить, что прямой доступ к элементу массива по индексу в typescript сохраняет тип instersction, x.lorems[0].bar; это нормально, но x.lorems.shift().bar; является ошибкой.

Ответ №2:

Мы можем создать тип util, который будет извлекать типы из вложенных массивов и создавать новый массив с типом intersected .

 export type IntersectionTypeWithArrays<T1, T2, arrayKeys extends (keyof T1 amp; keyof T2)> = (
    Omit<T1, arrayKeys> amp;
    Omit<T2, arrayKeys> amp; {
        [key in arrayKeys]: (
            (T1[key] extends Array<infer U1> ? U1 : never) amp; 
            (T2[key] extends Array<infer U2> ? U2 : never)
        )[]
    }
);
 

И позже пересечение типов будет выглядеть следующим образом:

 let x: IntersectionTypeWithArrays<LoremsFoo, LoremsBar, 'lorems'>;

x.lorems.shift().bar; // ok