Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

readonly array union cannot be searched

Tags:

typescript

I want to search an element inside an readonly array union

const areas = {
  area1: {
    adjacencies: [2, 3, 4, 5]
  },
  area2: {
    adjacencies: [6, 7, 8]
  }
} as const;
let area: keyof typeof areas;
if (Math.random() < 0.5) {
  area = "area1";
} else {
  area = "area2"
}

// Argument of type 'number' is not assignable to parameter of type 'never'
areas[area].adjacencies.includes(3);

I also tried indexOf, but it didn't work either. And I found the includes type is ReadonlyArray<T>.includes(searchElement: never, fromIndex: number | undefined): boolean .

I suppose the includes type should be the union of the elements of two readonly array, just like below:

const areas = {
  area1: {
    adjacencies: [2, 3, 4, 5]
  },
  area2: {
    adjacencies: [6, 7, 8]
  }
} as const;

type ValueOf<T extends object> = T[keyof T];
type Values = ValueOf<ValueOf<typeof areas>>
type ElementUnion = Values[number];

let area: keyof typeof areas;
if (Math.random() < 0.5) {
  area = "area1";
} else {
  area = "area2"
}

areas[area].adjacencies.includes(3);

How can I apply ElementUnion to includes or indexOf??

Here is the playground

like image 208
crazyones110 Avatar asked Sep 05 '26 09:09

crazyones110


1 Answers

When you do as const you tell typescript "even if encounter a literal like 0 or "hello", rather than inferring it as a general number or string, infer it literally".

So unless both of the arrays has the element you search for, it wont work.

const areas = {
  area1: {
    adjacencies: [2, 3, 4, 5]
  },
  area2: {
    adjacencies: [6, 7, 8, 3]
  }
} as const;

type ValueOf<T extends object> = T[keyof T];
type Values = ValueOf<ValueOf<typeof areas>>
type ElementUnion = Values[number];

let area: keyof typeof areas;
if (Math.random() < 0.5) {
  area = "area1";
} else {
  area = "area2"
}

areas[area].adjacencies.includes(3);

Notice how I added a 3 to the second array.

Playground

Edit:

Look at the signature of the function, only the union of the arrays can be passed to it.

(method) ReadonlyArray<T>.includes(searchElement: 3, fromIndex: number | undefined): boolean

Edit 2:
Example:

const areas = {
  area1: {
    adjacencies: [2, 3, 4, 5]
  },
  area2: {
    adjacencies: [6, 7, 8]
  }
} as const;

type ValueOf<T extends object> = T[keyof T];
type Values = ValueOf<ValueOf<typeof areas>>
type ElementUnion = Values[number];

let area: keyof typeof areas;

if (Math.random() < 0.5) {
  area = "area1";
} else {
  area = "area2"
}

// uh oh, .adjacencies can be either one of the arrays
// if the variable was declared without as const, the function would accept a number
// however since that it not the case, typescript takes the intersection
// (elements present in both arrays) as literal arguments
areas[area].adjacencies.includes(3);

///////////////////////////////////////////////////////////////
if (area === 'area1') {
  // here typescript knows what the elements are
  // but since the variable was declared as const, only literal values
  // that are in the array can be passed to the function
  //                          v Hover over this
  areas[area].adjacencies.includes(2);
} else {
  //                          v Hover over this
  areas[area].adjacencies.includes(6);
}

// Direct access
//                         v Hover over this
areas.area1.adjacencies.includes(2);
//                         v Hover over this
areas.area2.adjacencies.includes(6);
//                         v Hover over this
areas['area1'].adjacencies.includes(2)
//                         v Hover over this
areas['area2'].adjacencies.includes(6)

View in playground for hovers

Playground


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!