0

If I have a type like

export interface MyObject {
  id: number
  title: string
}

and I create an array like this

const myArray: MyObject[] = [
  {
    id: 2358,
    title: 'Item 1'
  },
  {
    id: 85373,
    title: 'Item 2'
  }
]

Is there a way to define a type that only allows values that have appeared as an id in the array? So in this case it would look like.

type DesiredType = 2358 | 85373

Here is a link to a Codewich where I have tried a few things to no avail.

Andrew McFaul
  • 203
  • 2
  • 9
  • Does this answer your question? [Is there a \`valueof\` similar to \`keyof\` in TypeScript?](https://stackoverflow.com/questions/49285864/is-there-a-valueof-similar-to-keyof-in-typescript) – choz Jul 07 '21 at 10:22

2 Answers2

3

To get the type of id in myArray you can use a type query: typeof myArray[number]['id']. The problem is that the type of id is not preserverd in the type of myArray.

To preserve the type you can use as const (but you loose the MyObject constraint)

const myArray = [
    {
        id: 2358,
        title: 'Item 1'
    },
    {
        id: 85373,
        title: 'Item 2'
    }
] as const;

type Id = typeof myArray[number]['id']

Playground Link

Or you can use a helper function:

function makeMyObjectArray<V extends number>(...a: Array<MyObject & { id: V}>) {
    return a;
}
const myArray = makeMyObjectArray(
    {
        id: 2358,
        title: 'Item 1'
    },
    {
        id: 85373,
        title: 'Item 2'
    }
)

type Id = typeof myArray[number]['id']

Playground Link

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
1

You can define a new type that has the type of the id property using, for example, Pick:

type MyObjectIdType = Pick<typeof myArray[number], 'id'>;

The problem here is that the array is a dynamic value and the compiler will infer the type as the most generic one, i.e., number. To have the compiler use the actual values of the id property you must tell it that the array is, in fact, a compile-time constant:

const myArray = [
    {
        id: 2358,
        title: 'Item 1'
    },
    {
        id: 85373,
        title: 'Item 2'
    }
] as const;

Note that for this to work I had to remove the type declaration MyObject[] from myArray, because a generic array of MyObject it is not compatible with the constant declaration (it may have more or less than 2 elements, with ids different from the given ones).

Obviously, this means that if you want to operate on a dynamic array, generated at runtime (and I expect you'd want), this will not work.

fog
  • 3,266
  • 1
  • 25
  • 31