Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f602315
Bump fast-xml-parser from 4.2.5 to 4.4.1 (#141)
dependabot[bot] Jul 30, 2024
12fd1be
Update CODEOWNERS
josephfusco Aug 26, 2024
d0dcaf6
Merge pull request #143 from wpengine/josephfusco-patch-1
josephfusco Aug 26, 2024
59d0309
Bump dset from 3.1.3 to 3.1.4 (#145)
dependabot[bot] Sep 12, 2024
bcbf291
Bump micromatch from 4.0.5 to 4.0.8 (#144)
dependabot[bot] Sep 12, 2024
557f492
Bump path-to-regexp from 6.2.1 to 6.3.0 (#147)
dependabot[bot] Sep 16, 2024
a1a94a9
Bump next from 14.1.1 to 14.2.12 (#148)
dependabot[bot] Sep 18, 2024
bce6800
Bump cross-spawn from 7.0.3 to 7.0.6
dependabot[bot] Nov 24, 2024
fc66cca
Merge pull request #191 from wpengine/dependabot/npm_and_yarn/cross-s…
josephfusco Nov 26, 2024
ec0b72c
added how to implement TS doc
Fran-A-Dev Dec 19, 2024
7896406
added fs naming and code block highlights
Fran-A-Dev Dec 19, 2024
e741c18
Merge branch 'toolkit' into doc/implement-TypeScript
moonmeister Dec 20, 2024
bdbec88
missed things
moonmeister Dec 20, 2024
6710317
merged toolkit updates
Fran-A-Dev Dec 20, 2024
5ef9e16
Resolved merge conflict in nav.json
Fran-A-Dev Dec 20, 2024
62ef152
Merge branch 'toolkit' into doc/implement-TypeScript
Fran-A-Dev Dec 30, 2024
07a5eea
removed graphql codegen and replaced it with updated auto generate co…
Fran-A-Dev Dec 30, 2024
b829c14
added steps on headers
Fran-A-Dev Dec 30, 2024
af5a8c4
added how to implement TS doc
Fran-A-Dev Dec 19, 2024
481e4e9
added fs naming and code block highlights
Fran-A-Dev Dec 19, 2024
38eeff2
missed things
moonmeister Dec 20, 2024
671ad7d
removed graphql codegen and replaced it with updated auto generate co…
Fran-A-Dev Dec 30, 2024
fb710ba
added steps on headers
Fran-A-Dev Dec 30, 2024
be9dc0b
misc cleanup
moonmeister Jan 2, 2025
31e7fb2
added changes to TS doc to make it more clear and purposeful
Fran-A-Dev Jan 3, 2025
c425d77
Merge remote-tracking branch 'origin/toolkit' into doc/implement-Type…
Fran-A-Dev Jan 3, 2025
3dba5de
Test commit using pnpm setup
Fran-A-Dev Jan 3, 2025
0ee5a79
merged conflicts and took care of conflict
Fran-A-Dev Jan 3, 2025
1811675
Update docs for clarity
kellenmace Jan 10, 2025
5173d95
Rename doc to 'generate-types-with-graphql-codegen' and remove the ol…
kellenmace Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
183 changes: 183 additions & 0 deletions src/pages/docs/how-to/implement-typescript/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
export const metadata = {
title: "Implement TypeScript",
};

## Implementing TypeScript

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

[View the Faust.js TypeScript scaffold application](https://github.com/wpengine/faust-scaffold-ts)

### Using graphql-codegen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we showing graphql codegen here? Don't we have our own generate command for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because it showed in the original docs here and it tells the user to consider it:
https://faustjs.org/guide/how-to-implement-typescript

Should I just do away with codegen @moonmeister ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my best guess is this doc was written before our built in generate command had shipped and it was never updated. Let's get that fixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good will fix it


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:

```ts title="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;
```

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:

```json title="package.json"
{
"scripts": {
...
"generate": "graphql-codegen",
}
}
```

> **_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:

```ts title="/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 };
```

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:

```ts title="src/wp-templates/single.tsx"
import { gql } from "../__generated__";

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

const Component: FaustTemplate<GetPostQuery> = (props) => {
...
}
```

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

![](./images/ts-image-one.png)

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

![](./images/ts-image-two.png)

## 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:

```ts title="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`,
};
```

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:

```ts title="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;
});
}
}
```

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

![](./images/typescript-fausthooks-type.png)

## 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](https://www.typescriptlang.org/docs/).

To summarize, you should use the following types available:

- `FaustTemplate`: For WP Template pages.
- `WordPressBlock`: For Block components.
- `GetStaticProps`, `GetServerSideProps`, and `GetStaticPaths`: For the result type of the Next.js `getStaticProps`, `getServerSideProps`, and `getStaticPaths` functions.
- `FaustHooks`: For the Plugin system hooks.

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

```ts title=" 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",
};
};
```

Here, since we are not exposing the type parameters of the `WordPressTemplate` function, you will need to extract them using the [Parameters](https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype) utility type:

```ts title="[...wordpressNode].tsx"
export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0];
```
9 changes: 8 additions & 1 deletion src/pages/docs/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
"title": "Basic Setup",
"route": "/docs/how-to/basic-setup/"
},

{
"title": "Implement TypeScript",
"route": "/docs/how-to/implement-typescript/"
},
{
"title": "Template Hierarchy",
"route": "/docs/how-to/template-hierarchy/"
},
{
"title": "Rendering Blocks",
"route": "/docs/how-to/rendering-blocks/"
Expand Down
Loading