Estoy usando objetos estáticos para describir definiciones de contratos e intento generar tipos basados en ellos. Estos contratos pueden tener opcionalmente algunas opciones, que quiero describir usando una serie de nombres de opciones. Luego quiero usar esta matriz para construir un tipo para pasar valores de opción. Todas las opciones deben ser obligatorias. Ver el siguiente código:
const definition = { optionNames: ['a', 'b'] as const }
type OptionNames = typeof definition['optionNames'][number]
// type OptionNames = "a" | "b"
type Options = Record<OptionNames, string>
// type Options = {
// a: string;
// b: string;
// }
Hasta ahora todo bien, puedo construir el tipo Opciones de forma estática sin ningún problema. Sin embargo, cuando trato de hacer lo mismo con los tipos genéricos, obtengo algunos resultados inesperados:
interface Definition { optionNames?: readonly string[] }
type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = T2 extends string | number | symbol? Record<T2, string>: {}
type GenericOptions = ConstructOptions<typeof definition>
// type GenericOptions = Record<"a", string> | Record<"b", string>
Espero que GenericOptions sea lo mismo que Opciones, sin embargo, el resultado es una unión de Registros que cada uno solo tiene 1 de las opciones como clave requerida. ¿Por qué está pasando esto?
Solución del problema
Use una tupla para asegurarse de que cada constituyente no se considere por separado:
type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = [T2] extends [string | number | symbol]? Record<T2, string>: {}
Ejemplo completo:
const definition = { optionNames: ['a', 'b'] as const }
interface Definition { optionNames?: readonly string[] }
type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = [T2] extends [string | number | symbol]? Record<T2, string>: {}
type GenericOptions = ConstructOptions<typeof definition>;
Una cosa extraña que probablemente nunca pensarías, pero funciona. Solo cosas de TypeScript aquí ✌️.
Patio de recreo
Por cierto, es posible que desee corregir ese error con NonNullableo Required;)
No hay comentarios:
Publicar un comentario