La restricción de tipos de TypeScript no funciona al iterar
Probablemente estoy perdiéndome algo obvio aquí, pero he estado atascado en esto por un tiempo.
Dado el siguiente predicado (Sé que técnicamente no es un predicado):
const hasProp = <K extends PropertyKey, T extends {}> (obj: T, prop: K): obj is T & Record<K, unknown> => {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
Quiero hacer algo como esto:
const coreProps = ['id', 'module', 'name', 'auth'] as const;
for (const prop of coreProps) {
if (!hasProp(rawObject, prop)) {
throw new Error(`Missing property '${prop}'`);
}
}
Sin embargo, esto no me permite usar, por ejemplo, rawObject.id después. Si desenrollo manualmente el bucle, funciona como se espera.
¿Estoy haciendo algo mal, o es esta una limitación del compilador de TypeScript?
Se me ocurrió esta alternativa:
const hasProps = <Ks extends PropertyKey[], T extends {}> (obj: T, ...props: Ks): obj is T & { [K in Ks[number]]: unknown } => {
return props.every(prop => hasProp(obj, prop));
}
Pero no me gusta esto, porque no devuelve ninguna información sobre qué propiedad falta (si es que falta alguna).
Respuesta #1
Creo que deberías usar la función assert para este propósito:
const hasProp = <K extends PropertyKey, T>(obj: T, prop: K): obj is T & Record<K, unknown> => {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
const rawObject: any = {}
const coreProps = ['id', 'module', 'name', 'auth'] as const;
type Props = typeof coreProps;
function assert(value: unknown): asserts value is Record<Props[number], unknown> {
for (const prop of coreProps) {
if (!hasProp(rawObject, prop)) {
throw new Error(`Missing property '${prop}'`);
}
}
}
assert(arg);// <---- assert function
arg.id // ok
Parque infantil
Ejemplos de funciones de aserción
Documentos oficiales de TS
Por lo tanto, para que funcione, deberías envolver tu bucle en función assert. De esta manera, TS puede inferir el tipo de tu objeto, de lo contrario no podrá hacerlo debido a la naturaleza mutable de los objetos.
