Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly type the _document.tsx file from Next.js?

I got most of this code from the official docs example on how to work with styled-components:

https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_document.js

But the example uses .js and I'm using Typescript.

I'm getting some type errors and warning and I'm not sure how to properly type it. I've already solved part of the problem. This is what I'm still missing:


Error 1: What should be the full signature type or the return type for the static async getInitialProps(ctx) function? What is the type for the ctx parameter?

enter image description here


Error 2: Unsafe access on ctx.renderPage. I guess this will be fixed once I properly type the getInitialProps function

enter image description here


Error 3: This is also probably related to the missing type for getInitialProps

enter image description here


import React, { ReactElement } from "react";
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
      originalRenderPage({
        enhanceApp: (App) => (props) =>
          sheet.collectStyles(<App {...props} />),
      });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render(): ReactElement {
    return(
      <Html lang="en">
        <Head>
          // SOMETHING IN THE HEAD
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
like image 531
cbdeveloper Avatar asked Apr 14 '21 08:04

cbdeveloper


People also ask

How do I use getInitialProps in NextJS?

getInitialProps is used to asynchronously fetch some data, which then populates props . Data returned from getInitialProps is serialized when server rendering, similar to what JSON.stringify does. Make sure the returned object from getInitialProps is a plain Object and not using Date , Map or Set .

What is TSX NextJS?

Incremental type checking support added when enabled in your tsconfig.json . Next.js provides an integrated TypeScript experience, including zero-configuration set up and built-in types for Pages, APIs, and more. Clone and deploy the TypeScript starter. View an example application.

How use CDN link in NextJS?

To set up a CDN, you can set up an asset prefix and configure your CDN's origin to resolve to the domain that Next. js is hosted on. The exact configuration for uploading your files to a given CDN will depend on your CDN of choice. The only folder you need to host on your CDN is the contents of .


1 Answers

This is what I've ended up doing to type the getInitialProps and render methods:

import React, { ReactElement } from "react";
import Document, { DocumentInitialProps, DocumentContext } from 'next/document';

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
    // ...
  }

  render(): ReactElement {
    return(
      // ...
    );
  }

}

https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_document.js

Full styled-components example:

import React, { ReactElement } from "react";
import Document, { Html, Head, Main, NextScript, DocumentInitialProps, DocumentContext } from 'next/document';
import { ServerStyleSheet } from "styled-components";

// NEXT.JS CUSTOM DOCUMENT
// https://nextjs.org/docs/advanced-features/custom-document

export default class MyDocument extends Document {
  
  static async getInitialProps(ctx: DocumentContext): Promise<DocumentInitialProps> {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
      originalRenderPage({
        enhanceApp: (App) => (props) =>
          sheet.collectStyles(<App {...props} />),
      });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render(): ReactElement {
    return(
      <Html lang="en">
        <Head>
          // SOME HEAD ELEMENTS
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
like image 188
cbdeveloper Avatar answered Oct 19 '22 21:10

cbdeveloper