I'm trying get uppercase version of a value in TS:
const directions = ['asc', 'desc'] as const
type Directions = typeof directions[number]
const [asc, desc] = directions
const order: Record<string, Uppercase<Directions>> = {
a: asc.toUpperCase(), // <- I need the type of this value to be 'ASC'
d: desc.toUpperCase(), // <- I need the type of this value to be 'DESC'
}
But because String.prototype.toUppercase returns string following error is thrown:
Type 'string' is not assignable to type '"ASC" | "DESC"'.
I found two solutions so far, but neither one of them are preferable:
1: use Type Assertion (as):
const order: Record<string, Uppercase<Directions>> = {
a: asc.toUpperCase() as Uppercase<Directions>,
d: desc.toUpperCase() as Uppercase<Directions>,
}
Con: Type safety is not guaranteed - order can be changed to something like
const order: Record<string, Uppercase<Directions>> = {
a: ''.toUpperCase() as Uppercase<Directions>,
d: ''.toUpperCase() as Uppercase<Directions>,
}
and TS won't complain.
2: create custom toUpperCase function with different signature
const toUpperCase = <T extends string>(input: T): Uppercase<T> => input.toUpperCase() as Uppercase<T>
const order: Record<string, Uppercase<Directions>> = {
a: toUpperCase(asc),
d: toUpperCase(desc),
}
Con: Developers have to be taught that they shouldn't use the built in function and it might confuse junior developers on whether they should use the built in method or the custom one.
Is there a type safe solution while using the native String.prototype.toUppercase method?