Write logic compatible with multiple different OSDK ObjectTypeDefinitions

I would like to write a function which can operate over any object set so long as the base object type contains a specific property. How can I do this?

What I’ve tried:

function filterMyProperty<
  OT extends ObjectTypeDefinition & {
    _DefinitionMetadata?: {
      properties: {
        myProperty: PropertyDef<"boolean", "nullable" | "non-nullable", "single">
      }
    }
  }
>(
  objectSet: ObjectSet<OT>,
  myPropertyValue: boolean
) {
  const whereClause: WhereClause<OT> = {
    myProperty: {
      $eq: myPropertyValue
    }
  };

  return objectSet.where(whereClause);
}

Unfortunately the where clause definition has a TypeScript error on myProperty: which reads Object literal may only specify known properties, and ‘myProperty’ does not exist in type ‘OrWhereClause<OT> | AndWhereClause<OT> | NotWhereClause<OT>’. ts(2353)

Below that, the VSCode mouse-over has (property) myProperty?: FilterFor<CompileTimeMetadata<OT>[“properties”][“myProperty”]> | undefined which should evaluate to a boolean filter, which I have provided.

Interestingly, the following is fine:

function filterMyProperty<
  OT extends ObjectTypeDefinition & {
    _DefinitionMetadata?: {
      properties: {
        myProperty: PropertyDef<"boolean", "nullable" | "non-nullable", "single">
      }
    }
  }
>(
  objectType: OT,
  myPropertyValue: boolean
) {
  return client(objectType).where({
    myProperty: {
      $eq: myPropertyValue
    },
    somePropertyThatDoesNotExistOnAnyObject: {}
  });
}

This ^ doesn’t show any TypeScript errors, though I think it should. Mousing over .where reveals any, which is why this doesn’t error.

A related question is how to do this ^ for an object set that contains the defined property either on the base object type or as one of the derived properties, or how to follow links, etc.

Generally examples around writing reusable logic over object sets would be very helpful: the typing of OSDK object/interface type definitions, object sets, and Osdk.Instance objects is extremely complicated (lots and lots and lots of layers of derived types, many of which are not exported from the SDK).

In general we recommend using Ontology Interfaces for these kinds of dynamic workflows. However, we are tracking that it is difficult to write generic functions over various object types due to the complexity of our TypeScript types.

1 Like

I don’t think interfaces work for what I have in mind: I think that would mean working in ObjectSet<MyInterface> instead of ObjectSet<MyObject>, which loses the details of MyObject.

Unless in the ontology I can define MyInterface, have MyObject implement that interface, and then in OSDK pass an ObjectSet<MyObject> to a function which takes ObjectSet<MyInterface> as input?

Thanks for the issue link - glad y’all are on it :slight_smile:

If you’re working at the level of individual Osdk.Instance<MyInterface>s then you could always access the full properties by fetching with $includeAllBaseObjectProperties: true and casting with .$as, but you’re correct that our types wouldn’t allow you to satisfy ObjectSet<MyInterface> with an ObjectSet<MyObject>.

A related new feature we’ve merged recently is Object Set Casting, but I’m not sure if this entirely fits your use case since it drops objects that aren’t of the base object type you cast to.