schema-dts
schema-dts copied to clipboard
Add support for custom attributes
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<---------------------------------------
};
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?
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.