Reputation: 12197
given this object literal...
const views = {
default: 'DEFAULT',
user: {
home: 'HOME',
profile: 'PROFILE'
}
}
I want to get a type like below without having to define it in multiple ways like defining a union type and then an object literal with all the types embedded
interface State {
view: `DEFAULT' | 'HOME' | 'PROFILE'
}
Can I achieve this in Typescript?
EDIT:
I could defined a union type of strings
type View = 'HOME' | 'DEFAULT' | 'PROFILE'
and then declare the object literal (with the same values as the type above) but then I would have to define it in multiple ways and I would be repeating myself
Upvotes: 2
Views: 2806
Reputation: 21971
If I got you correctly, this is what you want:
type View = 'HOME' | 'DEFAULT' | 'PROFILE'
interface Views {
[key: string]: View | Views
}
const views: Views = {
default: 'DEFAULT',
user: {
home: 'HOME',
profile: 'PROFILE'
},
wrong: 'SOME_STRING', // error
}
UPD, after comments. Now, if you want to object literal be a reference of all possible strings you could naively do this:
const views = {
default: 'DEFAULT',
user: {
home: 'HOME',
profile: 'PROFILE'
},
}
// Make some peculiar types to extract all the strings
type Views = typeof views
type Strings<Obj> = Obj[keyof Obj]
type FlatStrings<T> = T extends object ? T[keyof T] : T
type View = FlatStrings<Strings<Views>>
But guess what type does View
have? It's just string
! Not DEFAULT | HOME | PROFILE
as expected. Because typescript infers type string
from object literal strings unless you rewrite the object literal like this:
const views = {
default: 'DEFAULT' as const,
user: {
home: 'HOME' as const,
profile: 'PROFILE' as const
},
}
Upvotes: 5