question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Intersection of arrays

See original GitHub issue

Search Terms

intersection array

Suggestion

Intersections of arrays are weird in my opinion. In TypeScript 4.1, only the first part of the intersection is considered. I think TypeScript should merge the array types, it would be especially convenient for objects:

type A = { a: string }[];
type B = { b: number }[];
type C = A & B;

// Behaves like
C = { a: string }[];

// Desired
C = { a: string, b: number }[];

Playground to try it out.

Use Cases

I want to be able to cherry-pick some paths from an interface. I have an Elasticsearch cluster and a TypeScript interface for the shape of the documents in the cluster. With Elasticsearch, I’m able to retrieve only some values with their paths.

// With some documents of the following shape:
interface Post {
  id: string;
  views: number;
  comments: {
    id: string;
    content: string;
    author: {
      id: string;
    }
  }[];
}

// And a list of source fields
const sourceFields = ['id', 'comments.id'];

// When we do the query with these source fields, at runtime we only have a subset of the interface, like this:
{ id: '1', messages: [{ id: '1' }] };

Using features introduced in TypeScript 4.1 I’m able to generate a type based on the interface and the source fields. And it works almost perfectly except for arrays. While it works fine with nested objects, and nullable and optional keys.

Usage:

// Source fields are known at build time
const sourceFields = ['id', 'comments.id'] as const;

type ActualPost = PartialObjectFromSourceFields<Post, typeof sourceFields[number]>;
/* ActualPost behaves like
{
  id: string;
  comments: {
    id: string;
  }[];
}
*/

PartialObjectFromSourceFields declaration:

type ExtractPath<Obj, Path extends string> =
  Obj extends undefined ? ExtractPath<NonNullable<Obj>, Path> | undefined :
  Obj extends null ? ExtractPath<NonNullable<Obj>, Path> | null :
  Obj extends any[] ? ExtractPath<Obj[number], Path>[] :
  Path extends `${infer FirstKey}.${infer OtherPath}`
  ? (FirstKey extends keyof Obj
    ? { [k in FirstKey]: ExtractPath<Obj[FirstKey], OtherPath> }
    : never)
  : Path extends keyof Obj
    ? { [K in Path]: Obj[Path] }
    : never;

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type Distribute<Obj, Fields> = Fields extends string ? ExtractPath<Obj, Fields> : never;

export type PartialObjectFromSourceFields<Obj, Fields> = UnionToIntersection<Distribute<Obj, Fields>>

But because of the limitation on array intersection, as soon as 2 paths on an array key are used, only the first one is considered:

const sourceFields = ['id', 'comments.id', 'comments.content'] as const;

type ActualPost = PartialObjectFromSourceFields<Post, typeof sourceFields[number]>;

// ActualPost is in fact:
{ id: string } & { comments: { id: string }[] } & { comments: { content: string }[] };

// And `content` cannot be accessed inside `comments`, only `id` is available

Playground demo

Examples

I think the same merging rules should apply as without arrays:

type A = string[] & number[];

// Behaves like
A = string[]

// Desired?
A = never[];

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

I don’t know if it would be a breaking change 🤔 I wonder if it might conflict with this behavior https://github.com/microsoft/TypeScript/issues/38348

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:10 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
kasamachenkaowcommented, May 1, 2021

I found the workaround way to solve an issue I created ArrayIntersect<T1, T2> like this

hope it helps someone who needs the same use case like mine

2reactions
kasamachenkaowcommented, Apr 30, 2021

@RyanCavanaugh I see, thanks for clarification!

although I have 2 more questions:

  1. Why the issue is still open though?
  2. Why there is no bug tag attached to this issue (since if you access thru arr[0] you get both a and b but get only a in the map function?)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Intersection of Two Arrays - LeetCode
Given two integer arrays nums1 and nums2 , return an array of their intersection. Each element in the result must be unique and...
Read more >
Find Union and Intersection of two unsorted arrays
Given two unsorted arrays that represent two sets (elements in every array are distinct), find the union and intersection of two arrays.
Read more >
Find Intersection of Two Arrays - EnjoyAlgorithms
Given two integer arrays, X[] and Y[] of size m and n, write a program to find intersection of these two arrays. The...
Read more >
Array Intersection - Description - AlgoDaily
We can call the method intersection . Let's return the intersection of the two inputs in the form of an array. As a...
Read more >
350. Intersection of Two Arrays II - LEETCODE - YouTube
349. Intersection of Two Arrays | 350. Intersection of Two Arrays II | EASY | LEETCODE | 2 POINTERS.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found