Reputation: 63625
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
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:
typeof
in typeof currencies
.number
, so MyArray[number]
gets all members of that array as a union.value
property, you can drill into that to get a union of all possible types at that value
property."USD" | "EU"
"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