/** Rules to apply role */
interface RoleRule {
logic: "and" | "or";
rules: (
| {
source: "group" | "attribute";
group?: string;
attribute?: {
id: string;
operator: string;
value: string;
};
}
| RoleRule
)[];
}
/**
* Gets string representation of a rule.
*
* @param r Rule to get string representation of
* @returns String representation of rule
*/
const getRoleRuleString = (rule: RoleRule): string => {
const rulesStr: string[] = [];
rule.rules.forEach((r) => {
if (r.rules) {
// nested rules - recursively call this function
}
});
return rulesStr.join(` ${rule.logic} `);
};
So for the getRoleRuleString
function, I'm looping through the rules array of a RoleRule
. The idea is to recursively call the function if the element has a rules
property. However, I'm getting an error trying to check r.rules
.
Property 'rules' does not exist on type 'RoleRule | { source: "group" | "attribute"; group?: string | undefined; attribute?: { id: string; operator: string; value: string; } | undefined; }'.
Property 'rules' does not exist on type '{ source: "group" | "attribute"; group?: string | undefined; attribute?: { id: string; operator: string; value: string; } | undefined; }'
I managed to come up with this solution for it, but I feel like there is a more "corect" way of doing it.
if (rule.hasOwnProperty('logic')) {
const nestedAccess = rule as RoleRule;
rulesStr.push(`(${this.getFilterString(nestedAccess)})`);
}
I'm sure this has been asked before, but I just don't know how to properly google it, sorry about that.
CodePudding user response:
What you're looking for is called narrowing (formerly known as a type guard):
https://www.typescriptlang.org/docs/handbook/2/narrowing.html#the-in-operator-narrowing
JavaScript has an operator for determining if an object has a property with a name: the
in
operator. TypeScript takes this into account as a way to narrow down potential types.For example, with the code: "value" in x. where "value" is a string literal and x is a union type. The “true” branch narrows x’s types which have either an optional or required property value, and the “false” branch narrows to types which have an optional or missing property value.
type Fish = { swim: () => void }; type Bird = { fly: () => void }; function move(animal: Fish | Bird) { if ("swim" in animal) { return animal.swim(); } return animal.fly(); }