Skip To Main Content

Implementing TypeScript

Faust.js provides support for TypeScript including built-in types for Templates, Blocks and more.

Using graphql-codegen

First things first, you should consider using @graphql-codegen to generate types for the GraphQL queries.

Below is a sample config for generating the relevant typings:

//codegen.ts

import { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  schema: "https://faustexample.wpengine.com/graphql",
  documents: ["src/**/*.{tsx,ts}"],
  generates: {
    "./src/__generated__/": {
      preset: "client",
      plugins: [],
      presetConfig: {
        gqlTagName: "gql",
      },
    },
  },
  ignoreNoDocuments: true,
};

export default config;
Code language: JavaScript (javascript)

Add the following npm script that works by scanning the src folder for GraphQL queries and generating a bunch of files inside /src/__generated__/ for the TypeScript types:

// package.json

{
  "scripts": {
    ...
    "generate": "graphql-codegen",
  }
}
Code language: JavaScript (javascript)

Note: Be sure to enable WPGraphQL introspection before running the npm run generate command since it is disabled by default.

The most important file is the graphql.ts which contains all the schema types from the WPGraphQL endpoint plus the types of the queries:

// /src/__generated__/graphql.ts

...
export type GetPostQueryVariables = Exact<{
  databaseId: Scalars['ID'];
  asPreview?: InputMaybe<Scalars['Boolean']>;
}>;

export type GetPostQuery = { __typename?: 'RootQuery', post?: { __typename?: 'Post', title?: string | null, content?: string | null, date?: string | null, author?: { __typename?: 'NodeWithAuthorToUserConnectionEdge', node: { __typename?: 'User', name?: string | null } } | null } | null, generalSettings?: { __typename?: 'GeneralSettings', title?: string | null, description?: string | null } | null, primaryMenuItems?: { __typename?: 'RootQueryToMenuItemConnection', nodes: Array<{ __typename?: 'MenuItem', id: string, uri?: string | null, path?: string | null, label?: string | null, parentId?: string | null, cssClasses?: Array<string | null> | null, menu?: { __typename?: 'MenuItemToMenuConnectionEdge', node: { __typename?: 'Menu', name?: string | null } } | null }> } | null };

Code language: JavaScript (javascript)

You can use these types with the FaustTemplate helper which we will explain next.

How to apply types for WP Template Pages

When creating a new WP Template page, you can use the FaustTemplate to declare the type of the function component passing the type of the GraphQL query that was generated for that page:

// src/wp-templates/single.tsx

import { gql } from "../__generated__";

import { GetPostQuery } from "../__generated__/graphql";
import { FaustTemplate } from "@faustwp/core";

const Component: FaustTemplate<GetPostQuery> = (props) => {
    ...
}
Code language: JavaScript (javascript)

Then you can inspect all the types in the props parameters as you type:

All the data from the query results will be properly typed based on the introspected schema:

FaustTemplate prop data types

How to apply types for block components

Similarly, when creating Block components using @faustwp/blocks packages, you can use the WordPressBlock type that will include all the relevant properties of that block:

// src/wp-blocks/CoreParagraph.tsx

import { gql } from "../__generated__";
import { WordPressBlock } from "@faustwp/blocks";
import { CoreParagraphFragmentFragment } from "../__generated__/graphql";

const CoreParagraph: WordPressBlock<CoreParagraphFragmentFragment> = (
  props
) => {
  return <p>{props.attributes?.content}</p>;
};

export const fragments = {
  entry: gql(`
      fragment CoreParagraphFragment on CoreParagraph {
        attributes {
          content
        }
      }
    `),
  key: `CoreParagraphFragment`,
};
Code language: JavaScript (javascript)

Here we pass the CoreParagraphFragmentFragment type that corresponds to the CoreParagraphFragment fragment mapping all fields to TypeScript types. Then TypeScript will only allow the declared types to be used in the props parameter.

How to apply types for the plugin system

Faust providers a FaustHooks type that you can use for applying the corresponding type of the hooks parameter:

// src/plugins/ProjectTemplatePlugin.ts

import { FaustHooks, FaustPlugin } from '@faustwp/core';

export class ProjectTemplatePlugin implements FaustPlugin {
  constructor() {}

  apply(hooks: FaustHooks) {
    hooks.addFilter("possibleTemplatesList", "faust", (templates, data) => {
      if (data?.seedNode?.__typename === "Project") {
        return Array.from(new Set(["project", ...templates]));
      }
      return templates;
    });
  }
}
Code language: JavaScript (javascript)

Here the hooks parameter will autocomplete all correct types from each filter that is provided by the framework:

How to migrate existing pages to TypeScript

In general terms, most of the strategies for migrating existing pages to TypeScript should follow the relevant guide described in the TypeScript Docs.

To summarise, you should use the following types available:

  • FaustTemplate: For WP Template pages.
  • WordPressBlock: For Block components.
  • GetStaticPropsGetServerSideProps and GetStaticPaths: For the result type of the Next.js getStaticPropsgetServerSideProps and getStaticPaths functions.
  • FaustHooks: For the Plugin system hooks.

Let’s see an example of how to type the [...wordpressNode].tsx page:

// src/pages/[...wordpressNode].tsx

import { getWordPressProps, WordPressTemplate } from "@faustwp/core";
import { GetStaticPaths, GetStaticProps } from "next";

export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0];

export default function Page(props: WordPressTemplateProps) {
  return <WordPressTemplate {...props} />;
}

export const getStaticProps: GetStaticProps = (ctx) => {
  return getWordPressProps({ ctx });
};

export const getStaticPaths: GetStaticPaths = () => {
  return {
    paths: [],
    fallback: "blocking",
  };
};
Code language: JavaScript (javascript)

Here, since we are not exposing the type parameters of the WordPressTemplate function, you will need to extract them using the Parameters utility type:

export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0];
Code language: JavaScript (javascript)