I'm probably missing something obvious here, but I've been stuck on this one for a while.
Given the following predicate (I know it's not technically a predicate):
const hasProp = <K extends PropertyKey, T extends {}> (obj: T, prop: K): obj is T & Record<K, unknown> => {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
I want to do something like this:
const coreProps = ['id', 'module', 'name', 'auth'] as const;
for (const prop of coreProps) {
if (!hasProp(rawObject, prop)) {
throw new Error(`Missing property '${prop}'`);
}
}
However, this doesn't let me use e.g. rawObject.id
afterwards. If I manually unroll the loop, it works as expected.
Am I doing something wrong, or is this a limitation of the TypeScript compiler?
I did come up with this alternative:
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));
}
But I don't like this, because it doesn't return any information about which property is missing (if any).