Given
type PageInfo = {
title: string
key: string
}
const PAGES: PageInfo[] = [
{
key: 'trip_itinerary',
title: "Trip Itinerary",
},
{
key: 'trip_details',
title: "Trip Details",
},
{
key: 'passenger_info',
title: "Passenger Information",
},
]
Can I pull out a type for the key
key like 'trip_itinerary'|'trip_details'|'passenger_info'
? I want to use it as the key for a Record
, but I'd rather not write it manually.
Something like
type PageKey = typeof PAGES[???].key
I can swap PAGES
w/ satifies
if it helps...
const PAGES = [
...
] satisfies PageInfo[]
CodePudding user response:
If you annotate PAGES
as PageInfo[]
then the compiler will dutifully widen PAGES
to that type, allowing you to push()
arbitrary PageInfo
instances onto it, or rearrange its contents, or change the key
and properties on any of its elements. The compiler intentionally forgets about the specific order or contents of PAGES
and their particular properties, since these are subject to change. But that's not what you want.
Instead you want the compiler to infer the type of PAGES
. And if you want the inferred type to reflect literal types of the key
properties from the initializer, you will probably want to use a const
assertion to give the compiler a hint that you care about such specifics:
const PAGES = [
{
key: 'trip_itinerary',
title: "Trip Itinerary",
},
{
key: 'trip_details',
title: "Trip Details",
},
{
key: 'passenger_info',
title: "Passenger Information",
},
] as const;
Now PAGES
has the type
/* const PAGES: readonly [{
readonly key: "trip_itinerary";
readonly title: "Trip Itinerary";
}, {
readonly key: "trip_details";
readonly title: "Trip Details";
}, {
readonly key: "passenger_info";
readonly title: "Passenger Information";
}] */
and you can compute PageKey
as follows:
type PageKey = typeof PAGES[number]["key"];
// type PageKey = "trip_itinerary" | "trip_details" | "passenger_info"
This works as desired, and you could stop there if you want.
Still, the compiler won't care whether PAGES
is an array of PageInfo
elements or not. If you want the compiler to verify that type this without widening to it, you can use the satisfies
operator:
const PAGES = [
{
key: 'trip_itinerary',
title: "Trip Itinerary",
},
{
key: 'trip_details',
title: "Trip Details",
},
{
key: 'passenger_info',
title: "Passenger Information",
},
] as const satisfies readonly PageInfo[];
Note that we had to write satisfies readonly PageInfo[]
instead of satisfies PageInfo[]
. That's because the readonly X[]
array type is wider than the read-write X[]
array type. Since as const
produces readonly
arrays, then it isn't necessarily the case that PAGES satisfies PageInfo[]
.
Anyway now the compiler will complain if you fail to initialize PAGES
with valid PageInfo
elements:
const PAGES_OOPS = [
{
key: 'trip_itinerary',
title: "Trip Itinerary",
},
{
key: 'trip_details',
title: 123, // oops
},
{
key: 'passenger_info',
title: "Passenger Information",
},
] as const satisfies readonly PageInfo[] // error!
// Type '{ readonly key: "trip_details"; readonly title: 123; }'
// is not assignable to type 'PageInfo'.