-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Docs: TypeScript Development Guide (#1383)
* Docs: TypeScript Development Guide * Docs: Add missing code * Update internal/faustjs.org/docs/guides/typescript.mdx Co-authored-by: Blake Wilson <blake.wilson@wpengine.com> * Update internal/faustjs.org/docs/guides/typescript.mdx Co-authored-by: Blake Wilson <blake.wilson@wpengine.com> * Update internal/faustjs.org/docs/guides/typescript.mdx Co-authored-by: Blake Wilson <blake.wilson@wpengine.com> --------- Co-authored-by: Blake Wilson <blake.wilson@wpengine.com>
- Loading branch information
1 parent
d52fcdb
commit 7500e0d
Showing
5 changed files
with
195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
--- | ||
slug: /guides/typescript | ||
title: TypeScript | ||
description: Typescript development guide for Faust.js | ||
--- | ||
|
||
Faust.js provides support for [TypeScript](https://www.typescriptlang.org/) 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` | ||
|
||
First things first, you should consider using [@graphql-codegen](https://the-guild.dev/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](https://www.wpgraphql.com/docs/security#introspection-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: | ||
|
||
<img src="/docs/img/typescript-faust-template-props.png" alt="FaustTemplate prop types" /> | ||
|
||
All the data from the query results will be properly typed based on the introspected schema: | ||
|
||
<img src="/docs/img/typescript-faust-template-props-data-type.png" alt="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: | ||
|
||
```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: | ||
|
||
<img src="/docs/img/typescript-fausthooks-type.png" alt="FaustHooks prop data types" /> | ||
|
||
## 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](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html) described in the TypeScript Docs. | ||
|
||
To summarise, 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 | ||
export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0]; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+237 KB
internal/faustjs.org/static/docs/img/typescript-faust-template-props-data-type.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+71.5 KB
internal/faustjs.org/static/docs/img/typescript-faust-template-props.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7500e0d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out the recent updates to your Atlas environment:
Learn more about building on Atlas in our documentation.