Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom attributes #114

Open
sebastienlabine opened this issue Jul 17, 2020 · 3 comments
Open

Add support for custom attributes #114

sebastienlabine opened this issue Jul 17, 2020 · 3 comments

Comments

@sebastienlabine
Copy link

sebastienlabine commented Jul 17, 2020

Problem
Sometimes, we need to input a custom attribute in the Schema. For instance the sitelinks-searchbox structured data requires a query-input attribute that is not available in the schema.org representation. However, I can't add it manually, because the compiler will throw:

Object literal may only specify known properties, and '"query-input"' does not exist in type 'SearchActionLeaf'

potentialAction: {
    "@id":  `${process.env.NEXT_PUBLIC_WEBSITE_URL}/explore`,
    "@type": "SearchAction",
     target: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/explore/results?q={search_term_string}`,
    "query-input": "required name=search_term_string"
}

Solution
Add an attribute that let's you input a custom key value pair.

declare type ThingBase = Partial<IdReference> & {
    /** An additional type for the item, typically used for adding more specific types from external vocabularies in microdata syntax. This is a relationship between something and a class that the thing is in. In RDFa syntax, it is better to use the native RDFa syntax - the 'typeof' attribute - for multiple types. Schema.org tools may have only weaker understanding of extra types, in particular those defined externally. */
    "additionalType"?: SchemaValue<URL>;
    /** An alias for the item. */
    "alternateName"?: SchemaValue<Text>;
    /** A description of the item. */
    "description"?: SchemaValue<Text>;
    /** A sub property of description. A short description of the item used to disambiguate from other, similar items. Information from other properties (in particular, name) may be necessary for the description to be useful for disambiguation. */
    "disambiguatingDescription"?: SchemaValue<Text>;
    /** The identifier property represents any kind of identifier for any kind of {@link http://schema.org/Thing Thing}, such as ISBNs, GTIN codes, UUIDs etc. Schema.org provides dedicated properties for representing many of these, either as textual strings or as URL (URI) links. See {@link /docs/datamodel.html#identifierBg background notes} for more details. */
    "identifier"?: SchemaValue<PropertyValue | Text | URL | IdReference>;
    /** An image of the item. This can be a {@link http://schema.org/URL URL} or a fully described {@link http://schema.org/ImageObject ImageObject}. */
    "image"?: SchemaValue<ImageObject | URL | IdReference>;
    /** Indicates a page (or other CreativeWork) for which this thing is the main entity being described. See {@link /docs/datamodel.html#mainEntityBackground background notes} for details. */
    "mainEntityOfPage"?: SchemaValue<CreativeWork | URL | IdReference>;
    /** The name of the item. */
    "name"?: SchemaValue<Text>;
    /** Indicates a potential Action, which describes an idealized action in which this thing would play an 'object' role. */
    "potentialAction"?: SchemaValue<Action | IdReference>;
    /** URL of a reference Web page that unambiguously indicates the item's identity. E.g. the URL of the item's Wikipedia page, Wikidata entry, or official website. */
    "sameAs"?: SchemaValue<URL>;
    /** A CreativeWork or Event about this Thing. */
    "subjectOf"?: SchemaValue<CreativeWork | Event | IdReference>;
    /** URL of the item. */
    "url"?: SchemaValue<URL>;
    [extra: string]: string | ThingBase<---------------------------------------
};
@Eyas
Copy link
Collaborator

Eyas commented Jul 17, 2020

FWIW one workaround is mentioned in #33

This is a tough one to figure out, because [extra: string]: string | ThingBase effectively removes a lot of type checking that we talk about, e.g. if you type nmae instead of name, etc.

The two critical user journeys we want to address are (a) the IDE / completions experience and (b) tsc typechecking for obviously wrong/accidental input. Extra props remove (b), which might be an issue.

Writing your own XyzAction type especially works neatly if you're saving it as an intermediate variable. Since TS's excess property check only applies to object literals. So if you define this as:

// Available actions:
type QueryAction = SearchAction & {
  "query-input": string;
};

export const EXPLORE_ACTION: QueryAction = {
    "@id":  `${process.env.NEXT_PUBLIC_WEBSITE_URL}/explore`,
    "@type": "SearchAction",
     target: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/explore/results?q={search_term_string}`,
    "query-input": "required name=search_term_string"
};

// Elsewhere:

/* ... */ {
  // ...
  potentialAction: EXPLORE_ACTION
};

Does that work?

@sebastienlabine
Copy link
Author

That's what I was afraid of. I didn't really know how to keep both theses user journeys while including custom attributes.

The solution you provided should be good! I don't know how often we might need to create our own action but in my opinion we would benifit from having documentation on how to include custom attributes by creating custom types.

@lilouartz
Copy link

Can I just ignore the TypeScript error?

This is what I did for https://pillser.com

export const meta: MetaFunction = () => {
  return [
    { title: 'Pillser – Supplement Comparison Site' },
    {
      content: 'The best value for your money supplements.',
      name: 'description',
    },
    {
      href: 'https://pillser.com/',
      rel: 'canonical',
      tagName: 'link',
    },
    {
      '@context': 'https://schema.org',
      '@type': 'WebSite',
      description:
        'The best value for your money supplements. Find and compare supplements to get the most effective product for the best price.',
      name: 'Pillser – Supplement Comparison Site',
      potentialAction: {
        '@type': 'SearchAction',
        // @ts-expect-error - https://github.com/google/schema-dts/issues/114
        'query-input': 'required name=search_term_string',
        target: {
          '@type': 'EntryPoint',
          urlTemplate: 'https://pillser.com/search?q={search_term_string}',
        },
      },
      publisher: {
        '@type': 'Organization',
        logo: {
          '@type': 'ImageObject',
          url: 'https://www.pillser.com/pillser-logo.png',
        },
        name: 'Pillser',
      },
      url: 'https://www.pillser.com',
    } satisfies WithContext<WebSite>,
  ];
};

... or is this going to backfire somehow?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants