Tipos condicionales de TypeScript y typeof
Así que tengo este código que verifica que se construya el AnyOfTheAbove type a partir de una serie de constantes string:
const IT_COULD_BE_THIS = 'something';
const OR_THAT = 'something else';
const OR_EVEN = 'the other thing';
export type AnyOfTheAbove =
| typeof IT_COULD_BE_THIS
| typeof OR_THAT
| typeof OR_EVEN;
Me gustaría bastante poder escribir
export type AnyOfTheAbove = GetTypeof<
| IT_COULD_BE_THIS
| OR_THAT
| OR_EVEN
>;
O similar. Tengo la sensación de que puedo lograr esto con Tipos Condicionales. Pero todos mis intentos hasta ahora han fracasado. ¿Es esto posible?
Respuesta #1
No es posible ya que un tipo no aceptará un objeto en tiempo de ejecución que no esté precedido por typeof. (excepto para clases y enumeraciones)
Si realmente se trata de no escribir typeof para cada objeto, puedes envolver todos los objetos en una llamada a función, y luego extraer los tipos una vez usando typeof:
Usando función falsa
// No value produced at runtime, but infers union type statically
function unionType<T>(...arr: T[]): T { return null as unknown as T }
const IT_COULD_BE_THIS = 'something'
const OR_THAT = 'something else'
const OR_EVEN = 'the other thing'
// Extract types from function call
type AnyOfTheAbove = typeof AnyOfTheAbove
const AnyOfTheAbove = unionType(
IT_COULD_BE_THIS,
OR_THAT,
OR_EVEN
)
Lo que implica una llamada en tiempo de ejecución (que solo devolverá null), pero permite sortear la limitación.
Usando tupla
// You need to specify `string` to infer each string correctly:
// https://github.com/Microsoft/TypeScript/issues/26158
function tuple<T extends string[]>(...t: T) { return t }
const IT_COULD_BE_THIS = 'something'
const OR_THAT = 'something else'
const OR_EVEN = 'the other thing'
// Extract types from function call
type AnyOfTheAbove = typeof AllOfTheAbove[number]
const AllOfTheAbove = tuple(
IT_COULD_BE_THIS,
OR_THAT,
OR_EVEN
)
De hecho, ambas soluciones utilizan Tuple, pero una implica una llamada de ejecución falsa, mientras que la otra simplemente envolverá tu array en una llamada de función para inferir correctamente los tipos.
Ninguno realmente ahorra caracteres ni simplifica la legibilidad.
Editar 26/08/2019
Usando Enum
Si puedes definir todas estas cadenas en un enum, puedes hacer:
enum AllEnum {
IT_COULD_BE_THIS,
OR_THAT,
OR_EVEN,
}
// Static type
type All = keyof typeof AllEnum
// Access all strings at runtime
const allAtRuntime = Object.keys(AllEnum)
