opensas
opensas

Reputation: 63625

Define a TypeScript type from the values of an object array

Given the following array:

type Currency = {
  text: string,
  value: string
}

let currencies: Currency[] = [ 
  { text: 'American dollars', value: 'USD' },
  { text: 'Euros', value: 'EU' }
]

These currencies might come from a database or a web service, but will have that shape, that is: { text: string, value: string }[].

Is there some way to define a variable like this:

let currency: 'USD' | 'EU'

That is, a type which should be the value property of one item of the currencies array.

What would be the right way to define these types so I can enforce that currency holds a valid currency value?

Upvotes: 1

Views: 687

Answers (1)

Alex Wayne
Alex Wayne

Reputation: 187272

Sure can.

const currencies = [ 
  { text: 'American dollars', value: 'USD' },
  { text: 'Euros', value: 'EU' }
] as const

type CurrencyName = (typeof currencies)[number]['value'] // "USD" | "EU"

let currency: CurrencyName = 'USD' // works

First of all, currencies needs to be a const and as const this tells typescript that these are constant literals and not just any old string.

Then:

  • You can get the type of a value with typeof in typeof currencies.
  • This is an array. Array's are indexed by number, so MyArray[number] gets all members of that array as a union.
  • All union members have a value property, you can drill into that to get a union of all possible types at that value property.
  • The result is "USD" | "EU"

Playground


"The data may eventually come from a database or a web service, but it will still be an array of Currency. Is there some way to let typescript know that currency is meant to match the value prop of an item from the currencies array?"

Not really. Typescript is structural, not nominal. That means that if two types have the same shape, then it considers them the same type.

So if these records are stored in a database, the value column will be typed as string since you can't know the union of values at compile time. And that means any string will be considered the same as that type.

To elaborate on this further would drift into a totally separate SO question. So feel free to ask another!

Upvotes: 2

Related Questions