In coding practice, a specific convention involves denoting the child of an entity (meaning an association with another entity) with a '$' symbol.
class Pet {
owner$: any;
}
When making a reference to an entity child, users should have the option to use either the full form ('owner$') or a simplified form ('owner').
One attempt at implementing this concept is shown below:
type ChildAttributeString = `${string}\$`;
type ShortChildAttribute<E> = ((keyof E) extends `${infer Att}\$` ? Att : never);
type ChildAttribute<E> = (keyof E & ChildAttributeString) | ShortChildAttribute<E>;
const att1: ChildAttribute<Pet> = 'owner$'; // Successfully matches the valid type
const att2: ChildAttribute<Pet> = 'owner'; // Successfully matches the valid type
const att3: ChildAttribute<Pet> = 'previousOwner$'; // Invalid: 'previousOwner$' is not an attribute of Pet - As expected
This approach works fine when all attributes of Pet are considered child attributes. However, if a non-child attribute is added, the matching process breaks down:
class Pet {
name: string;
owner$: any;
}
const att1: ChildAttribute<Pet> = 'owner$'; // Successfully matches the valid type
const att2: ChildAttribute<Pet> = 'owner'; // INVALID: Type 'string' cannot be assigned to type 'never'
// To clarify: ChildAttribute<Pet> should accept values like 'owner' and 'owner$', but not 'name' which is not a child attribute (lacks the trailing '$')
What would be the appropriate types to ensure this functionality works as intended?
--- edit
To avoid confusion about the desired outcome and the definition of an "entity child", I have modified the question for clarity.