Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Possible to have generic constraints in Arrays?

Is it possible to have TypeScript constrain the 2nd index using the first argument?

For example:

type Data = {
  FOO: number
  BAR: string
}

type DataKeys = keyof Data

type SpecialArray<T extends DataKeys = DataKeys> = [T, Data[T]]

// I want both of these array to fail because the 2nd argument's type
// is determined by the first argument
const arr1: SpecialArray = ['FOO', 'wrong'] // 2nd argument should be `number`
const arr2: SpecialArray = ['BAR', 666] // 2nd argument should be `string`

// This works well with functions
const specialFunction = <T extends DataKeys = DataKeys>(key: T, value: Data[T]) => {
  return
}
specialFunction('FOO', 'wrong')
specialFunction('BAR', 666)

Link to playground

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Yes and no.

In this case:

type SpecialArray<T extends DataKeys = DataKeys> = [T, Data[T]]
const arr1: SpecialArray = ['FOO', 'wrong'] // no error

You omitted the generic parameter, so the default is used. And since the default type DataKeys is all keys then the resulting value type is number | string.

However, all generic parameters must have a type assigned to them, so it doesn’t work if you only remove the default:

type SpecialArray<T extends DataKeys> = [T, Data[T]]
const arr1: SpecialArray = ['FOO', 'wrong'] // error
// Generic type 'SpecialArray' requires 1 type argument(s).(2314)

It does work if you specify the generic parameter:

// errors as expected
const arr1: SpecialArray<'FOO'> = ['FOO', 'wrong'] // 2nd argument should be `number`
const arr2: SpecialArray<'BAR'> = ['BAR', 666] // 2nd argument should be `string`

But that’s not exactly pretty.

Sadly, you just can’t infer a generic parameter from a simple assignment in typescript.

The typical workaround for this is to use a function to make the objects for you. Since, as you note functions handle this better.

function makeSpecialArray<
  T extends DataKeys
>(key: T, value: Data[T]): SpecialArray<T> {
  return [key, value]
}

// these are type errors, and the objects they create are SpecialArray<SomeKey>
const arr1 = makeSpecialArray('FOO', 'wrong') // 2nd argument should be `number`
const arr2 = makeSpecialArray('BAR', 666) // 2nd argument should be `string`

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading