GOOGLE ADS

miércoles, 13 de abril de 2022

Tipo asignado que produce resultados inesperados cuando se crea a partir de un tipo genérico

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

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...