Chris Drackett
Chris Drackett

Reputation: 1327

How to enforce types within object while letting key be "fixed" in typescript?

I have an object in a project that I'm trying to type:

export const dateFormat = {
  hourOnly: { hour: 'numeric' }
  …
}

I know that the values in this object should fit Intl.DateTimeFormatOptions so I tried:

export const dateFormat: {[key: string]: Intl.DateTimeFormatOptions} = {
  hourOnly: { hour: 'numeric' }
  …
}

This works but I lose the ability to get auto complete for this object elsewhere in the project. I tried adding as const at the end, but that didn't help.

Is there a way to enforce an objects values while still getting auto-complete for the keys?

I also tried:

type dateFormatOptions = 'hourOnly'

export const dateFormat: {[key: dateFormatOptions]: Intl.DateTimeFormatOptions} = {
  hourOnly: { hour: 'numeric' }
  …
}

but in this case typescript says the index signature should be a string or a number?

Upvotes: 0

Views: 44

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250336

If you know the keys you can just use Record to create a type that has those explicit keys of the type you want (Record is called a mapped type)

type dateFormatOptions = 'hourOnly'

export const dateFormat: Record<dateFormatOptions, Intl.DateTimeFormatOptions> = {
  hourOnly: { hour: 'numeric' }
}

This does require you to keep the names of the properties in two places. Another option is to use a function with a constrained generic type parameter. The type parameter constraint will keep all values of the specified type but the actual keys will be inferred based on the object you pass in.

function createDateFormatOptions<K extends PropertyKey>(o: Record<K, Intl.DateTimeFormatOptions>): Record<K, Intl.DateTimeFormatOptions> {
    return o;
}
export const dateFormat = createDateFormatOptions({
  hourOnly: { hour: 'numeric' },
})

Upvotes: 1

Related Questions