Getting plugin-seo to work with TypeScript

default discord avatar
\ ឵឵឵
11 months ago

As an example:

import { default as _seo } from '@payloadcms/plugin-seo';
import { Page } from '../payload-types';

export const seo = _seo({
  collections: ['pages'],
  uploadsCollection: 'media',
  generateTitle: ({ doc }: { doc: Page; locale?: string }) => `My Site — ${doc.title}`,
  generateDescription: ({ doc }) => doc.excerpt,

With the typing for


's args,


is happy, but


is not, because


is more specific than the

T = any

type. Without the typing, as in the example


, it chokes on


not having an



Mightn't it be possible for the library to type


as the union of the collection types specified? Or what are people doing here?


  • discord user avatar
    Payload Team
    11 months ago

    @jacobsfletch you may want to take a peek at this one

  • discord user avatar
    Payload Team
    11 months ago

    It does look like those functions type the doc, check this out:

    So you should type your whole function instead of just the args, then pass in the generic. Something like this:

    export const generateTitle: PluginConfig['generateTitle']<Page> = ({ doc }) => {
        // 'doc' should be typed as 'Page'

    It looks like the plugin doesn't explicitly export function types which is why it's written this way. The readme says you can import


    but I'm not sure this is true.

  • default discord avatar
    \ ឵឵឵
    11 months ago

    Hmm, when I do that I get a syntax error on the opening angle brace for



    const generateTitle: PluginConfig['generateTitle']<Page> = ({doc}) => `My Site — doc.title`

    ',' expected.ts(1005)

    Possibly this sheds some light:

    type GenerateTitle = PluginConfig['generateTitle'];
    const generateTitle: GenerateTitle<Page> = ({ doc }) => `My Site — ${doc.title}`;

    Type 'GenerateTitle' is not generic.ts(2315)

    Perhaps the author was trying to make it a template function, but ended up with a type variable instead?


    type GenerateTitleX<T = any> = (args: { doc: T }) => string;
    const generateTitleXTyped: GenerateTitleX<Page> = ({ doc }) => `My Site — ${doc.title}`;
    const generateTitleXUntyped: GenerateTitleX = ({ doc }) => `My Site — ${doc.title}`;

    I'm reasonably sure that's what the author intended, given the type variable


    in the current implementation is unused.

    I haven't really dug into that part of payload so much, maybe you know whether or not payload has something which can infer the type from a collection slug? Otherwise if people want typing it needs to be supplied explicitly as a parameter to the generic. With

    <T = any>

    , you won't get any errors—but there also won't be any inference.

    <T = unknown>

    if we want to force users to be explicit.

  • default discord avatar
    8 months ago

    did this ever get resolved? also experiencing the same problem with typing the doc, and came to the same conclusion that the types have been written incorrectly. you should just be able to pass in a type with


    and have the doc typed that way

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!


Connect with the Payload Community on Discord



Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.