Así que tengo este objeto constante
const STUDY_TAGS ={ InstanceAvailability: { tag: "00080056", type: "optional", vr: "string" }, ModalitiesinStudy: { tag: "00080061", type: "required", vr: "string" }, ReferringPhysiciansName: { tag: "00080090", type: "required", vr: "string" }, NumberofStudyRelatedSeries: { tag: "00201206", type: "required", vr: "number", } };
Ahora quiero inferir el tipo de devolución de cada objeto en función de su valor vr, pero si observo el tipo de STUDY_TAGS, todos los pares clave-valor tienen el mismo aspecto:
InstanceAvailability: { tag: string; type: string; vr: string; };
¿Puedo de alguna manera forzar el mecanografiado para mantener los literales de cadena en lugar de generalizarlos a la cadena de tipo? Pensé en definir el Objeto con el tipo Registro<cadena, {etiqueta: cadena, tipo: cadena, vr: "cadena" | "number"}> pero luego todo lo que obtengo cuando miro typeof STUDY_TAGS es
Record<string, { tag: string; type: string; vr: "string" | "number"; }
Estoy realmente perdido aquí y no tengo idea de cómo resolver este problema. ¿No debería ser posible de alguna manera inferir el tipo de retorno basado en un objeto que tiene uno de los 2 valores de cadena? Al final, quiero crear una función que tome el objeto y conozca el tipo devuelto en función del valor vr.
function doSomething<Type extends "number" | "string">({tag, type, vr} : {tag : string, type : string, vr: Type}) : Type extends "number" ? number : string { if(vr === "string") return "test"; return 0; }
Mi problema principal era no obtener la información de tipo del objeto porque generalizaría mis constantes de cadena a la cadena de tipo general, aunque definí mi objeto con Object.freeze()
. La solución fue definir el objeto así:
const obj = {a: {test: "hi"}} as const;
Debería poder declarar los tipos 'como const'
const STUDY_TAGS ={ InstanceAvailability: { tag: "00080056", type: "optional" as const, vr: "string" }, ModalitiesinStudy: { tag: "00080061", type: "required" as const, vr: "string" }, ReferringPhysiciansName: { tag: "00080090", type: "required" as const, vr: "string" }, NumberofStudyRelatedSeries: { tag: "00201206", type: "required" as const, vr: "number", } };
Arriba, acabo de agregar 'as const' para la propiedad de type
para que pueda ver la diferencia. Puede agregarlos a cualquiera de las propiedades anteriores para obtener los valores exactos en lugar de sus valores primitivos.
Creo que la sobrecarga y el estrechamiento de funciones podrían ayudarlo. He aquí un ejemplo simplificado:
function doSomething(vr: 'string'): string function doSomething(vr: 'number'): number function doSomething(vr: string): string | number { if(vr === 'string) return 'Test!'; return 0; }
Luego, cuando llamas a doSomething
, el sistema de tipeo de TypeScript puede inferir el tipo de retorno, porque lo indicaste siempre que vr
es igual a 'string'
, la función devuelve una cadena, y siempre que vr
es igual a 'number'
, la función devuelve un número .
const foo = doSomething('string'); // TypeScript knows 'foo' is a string const bar = doSomething(2); // TypeScript know 'bar' is a number
Aquí hay un ejemplo más completo con su caso de uso específico en el patio de recreo de TypeScript.