I have a country configuration which looks as such:
type CountryConfig = {
[country: string]: {
countryCode: string,
callingCode: string,
...
}
}
const balkanCountries: CountryConfig = {
Albania: { countryCode: "AL", callingCode: "+355", ... },
Bulgaria: { countryCode: "BG", callingCode: "+359", ... },
Croatia: { countryCode: "HR", callingCode: "+385", ... },
...
}
I want to create a type from the keys of balkanCountries:
type BalkanCountry = keyof typeof balkanCountries
Expected type: BalkanCountry = "Albania" | "Bulgaria" | "Croatia" | ..., actual type: BalkanCountry = string | number.
Based on the answer in this Stack Overflow thread this is expected behaviour and I can get around the number type by explicitly extracting the string as such:
type BalkanCountry = Extract<keyof typeof balkanCountries, string>
However, the output type I get is still type BalkanCountries = string and not a union of literals.
This means I can do assignment as:
const currentCountry: BalkanCountry = "Spain" // typescript will not throw error
Why this is happening? How can I ensure currentCountry can only be a value that is a key in balkanCountries?
Note: I am using TypeScript ~5.0.4.
>Solution :
You will have to drop the type definition to infer the keys from the object.
const balkanCountries = {
Albania: { countryCode: "AL", callingCode: "+355" },
Bulgaria: { countryCode: "BG", callingCode: "+359", },
Croatia: { countryCode: "HR", callingCode: "+385", },
} satisifies CountryConfig;
type BalkanCountry = keyof typeof balkanCountries
// "Albania" | "Bulgaria" | "Croatia"
The satisfies operator (introduced in TS 4.9), will ensure the type safety.