google / schema-dts

JSON-LD TypeScript types for Schema.org vocabulary
Apache License 2.0
860 stars 32 forks source link

'@type' as array #189

Open TomRadford opened 1 year ago

TomRadford commented 1 year ago

Was wondering if it would be possible to use the @type in an array. My use case would be in the context of utilizing two types like this: '@type': (['Car', 'Product'] currently working around this by casting to one of the types '@type': (['Car', 'Product'] as unknown as 'Car')

Would be keen to hear if this would be possible?

Eyas commented 1 year ago

Yeah this is also discussed in #179. There are a few issues here.

In general, you can construct your own type as a workaround:

import {Car, Product} from 'schema-dts';

type CarProduct = Omit<Car & Product, '@type'> & { "@type": ["Car", "Product"] }

const c: CarProduct = {
    "@type": ["Car", "Product"],
    "name": "abc",
    "roofLoad": {"@type": "QuantitativeValue"},
};

The problem with generic support, however, is that it's really easy to multiple @types for different "leaf" types, but its harder if we're trying to create types that understand subtypes of each item in the array as well.

curtisburns commented 11 months ago

This doesn't seem to work with ArtGallery and Organization. I've just tried this solution, but apparently, none of the properties exist now - @id, name, sameAs, etc. Is there a workaround for this?

curtisburns commented 11 months ago

For anyone else facing the same issue, I've resorted to the following for now:

type ArtGalleryOrganization = {
  '@type': ['ArtGallery', 'Organization'];
  '@id': Exclude<Organization, string>['@id'];
  name: Exclude<Organization, string>['name'];
  url: Exclude<Organization, string>['url'];
  logo: Exclude<Organization, string>['logo'];
  image: Exclude<Organization, string>['image'];
  founder: Exclude<Organization, string>['founder'];
  description: Exclude<Organization, string>['description'];
  sameAs: Exclude<Organization, string>['sameAs'];
  address: Exclude<Organization, string>['address'];
  location: Exclude<Organization, string>['location'];
  openingHours: Exclude<ArtGallery, string>['openingHours'];
  event: Exclude<Organization, string>['event'];
};

Seeing as ArtGallery is a sub-class of Organization, I only really use the one specific property with the rest coming from Organization.

Also using the Exclude<T, U> method as referencing properties like Organization['sameAs] doesn't seem to work. Obviously not ideal if you need to be aware of all the properties available for Organization and ArtGallery, but not too big of an issue for me. If there's a better way to do this let me know! Cheers.