'Is it possible to distinguish between a subset of an array?

Sorry for the bad title, I didn't know how to explain it better in one sentence.

I'll just paste the code I have so far, because I believe it should be quite self-explanatory.

// I have a columns const that never changes
const columns = ["a", "b", "c"] as const

// I have editable columns, that is a subset of columns,
// which also never changes, so I make it readonly.
type EditableColumns = readonly (typeof columns[number])[]

// In this case, a and b are editable, c is not.
const editableColumns: EditableColumns = ["a", "b"] as const

type Props<T> = { data: readonly T[], editableColumns: EditableColumns }

// Now what I'm trying to accomplish here...
// is that I want any of the editable columns to get some extra info,
// and I want all of the other columns to NOT get that extra info.
type Foo<U, T extends Props<U> = Props<U>> = {
  [key in typeof columns[number]]: key extends T["editableColumns"][number]
    ? {
        readonly column: key
        readonly row: U
        readonly extraInfo: "HELLO"
      }
  : {
      readonly column: key
      readonly row: U
    }
}

let foo = {} as Foo<string>

// But right now, as you can see,
// ALL the columns get the extra info.
// Even though I didn't want foo.c to get the extra info.
// You can see that when you mouseover foo.c
foo.a
foo.b
foo.c

// How do I make sure that a and b are included and c is excluded?

playground link



Solution 1:[1]

Your const editableColumns is not referenced anywhere in your Foo type definition. If you change it as follows, foo.c will be restricted as per your requirements:

const columns = ["a", "b", "c"] as const;

type EditableColumns = readonly (typeof columns[number])[];

const editableColumns = ["a", "b"] as const;

type Props<T> = { data: readonly T[], editableColumns: EditableColumns };

type Foo<U> = {
  [key in typeof columns[number]]: key extends (typeof editableColumns)[number]
    ? {
        readonly column: key
        readonly row: U
        readonly extraInfo: "HELLO"
      }
  : {
      readonly column: key
      readonly row: U
    }
};

let foo = {} as Foo<string>;
foo.a;
foo.b;
foo.c;

Not very clear what you're actually trying to achieve though.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Robby Cornelissen