mirror of
https://github.com/zhigang1992/DefinitelyTyped.git
synced 2026-05-28 08:17:54 +08:00
[next] Elaborate on Document types
Adjust renderPage and Enhancer; add tests Allows Enhancer to receive a React ComponentType that accepts one set of props and return a ComponentType that accepts a different set of props, the latter including at least url
This commit is contained in:
49
types/next/document.d.ts
vendored
49
types/next/document.d.ts
vendored
@@ -1,10 +1,43 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { NextContext } from ".";
|
||||
|
||||
export interface RenderPageResponse {
|
||||
buildManifest: { [key: string]: any };
|
||||
chunks: {
|
||||
names: string[];
|
||||
filenames: string[];
|
||||
};
|
||||
html?: string;
|
||||
head: Array<React.ReactElement<any>>;
|
||||
errorHtml: string;
|
||||
}
|
||||
|
||||
export interface PageProps {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface AnyPageProps extends PageProps {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type Enhancer<E extends PageProps = AnyPageProps, P extends any = E> = (page: React.ComponentType<P>) => React.ComponentType<E>;
|
||||
|
||||
/**
|
||||
* Context object used inside `Document`
|
||||
*/
|
||||
export interface NextDocumentContext extends NextContext {
|
||||
/** A callback that executes the actual React rendering logic (synchronously) */
|
||||
renderPage<E extends PageProps = AnyPageProps, P extends any = E>(enhancer?: Enhancer<E, P>): RenderPageResponse; // tslint:disable-line:no-unnecessary-generics
|
||||
}
|
||||
|
||||
export interface DocumentProps {
|
||||
__NEXT_DATA__?: any;
|
||||
dev?: boolean;
|
||||
chunks?: string[];
|
||||
chunks?: {
|
||||
names: string[];
|
||||
filenames: string[];
|
||||
};
|
||||
html?: string;
|
||||
head?: Array<React.ReactElement<any>>;
|
||||
errorHtml?: string;
|
||||
@@ -13,21 +46,9 @@ export interface DocumentProps {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context object used inside `Document`
|
||||
*/
|
||||
export interface NextDocumentContext extends NextContext {
|
||||
/** A callback that executes the actual React rendering logic (synchronously) */
|
||||
renderPage(
|
||||
cb?: (enhancer: () => JSX.Element) => React.ComponentType<any>
|
||||
): {
|
||||
[key: string]: any
|
||||
};
|
||||
}
|
||||
|
||||
export class Head extends React.Component<any> {}
|
||||
export class Main extends React.Component {}
|
||||
export class NextScript extends React.Component {}
|
||||
export default class extends React.Component<DocumentProps> {
|
||||
static getInitialProps(ctx: NextContext): DocumentProps;
|
||||
static getInitialProps(ctx: NextDocumentContext): Promise<DocumentProps> | DocumentProps;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Document, { Head, Main, NextScript, NextDocumentContext } from 'next/document';
|
||||
import Document, { DocumentProps, Enhancer, Head, Main, NextScript, NextDocumentContext, PageProps } from 'next/document';
|
||||
import * as React from "react";
|
||||
|
||||
const results = (
|
||||
const basicResults = (
|
||||
<Document any="property" should="work" here>
|
||||
<Head some="more" properties>
|
||||
<meta name="description" content="Head can have children, too!" />
|
||||
@@ -38,3 +38,66 @@ export default class MyDocument extends Document {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyDoc extends Document {
|
||||
static async getInitialProps({ renderPage }: NextDocumentContext) {
|
||||
const enhancer: Enhancer<PageProps, {}> = (App) => (props) => (<App />);
|
||||
const { html, head, errorHtml, chunks, buildManifest } = renderPage(enhancer);
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
return { html, head, errorHtml, chunks, buildManifest, now };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<html>
|
||||
<Head>
|
||||
<title>My page</title>
|
||||
rendered at {this.props.now}
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
{this.props.children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const extendedResults = (
|
||||
<MyDoc any="property" should="work" here>
|
||||
<Head some="more" properties>
|
||||
<meta name="description" content="Head can have children, too!" />
|
||||
</Head>
|
||||
<h1>Hey there</h1>
|
||||
</MyDoc>
|
||||
);
|
||||
|
||||
const renderPage: NextDocumentContext['renderPage'] = (enhancer) => ({
|
||||
buildManifest: {},
|
||||
chunks: { names: [], filenames: [] },
|
||||
html: '',
|
||||
head: [<React.Fragment />],
|
||||
errorHtml: '',
|
||||
});
|
||||
|
||||
interface PageInitialProps extends PageProps {
|
||||
foo: string;
|
||||
bar: number;
|
||||
}
|
||||
|
||||
interface ProcessedInitialProps {
|
||||
fooLength: number;
|
||||
bar: boolean;
|
||||
}
|
||||
|
||||
const enhancerExplicit: Enhancer<PageProps, {}> = (App) => (props) => (<App />);
|
||||
const enhancerInferred = (App: React.ComponentType<ProcessedInitialProps>) => ({ foo, bar }: PageInitialProps) => (<App fooLength={foo.length} bar={!!bar} />);
|
||||
const explicitEnhancerRenderResponse = renderPage(enhancerExplicit);
|
||||
const inferredEnhancerRenderResponse = renderPage(enhancerInferred);
|
||||
const defaultedTypesRenderResponse = renderPage((App) => (props) => (<App url={props.url} />));
|
||||
const defaultedTypesExtendedRenderResponse = renderPage((App) => (props) => (<App foo="bar" url={props.url} />));
|
||||
const explicitTypesRenderResponseOne = renderPage<PageProps, {}>((App) => (props) => (<App />));
|
||||
const explicitTypesRenderResponseTwo = renderPage<PageInitialProps, ProcessedInitialProps>((App) => ({ foo, bar }) => (<App fooLength={foo.length} bar={!!bar} />));
|
||||
|
||||
Reference in New Issue
Block a user