Merge pull request #17781 from Dru89/nextjs-types

Add types for next.js
This commit is contained in:
Ryan Cavanaugh
2017-07-10 12:25:55 -07:00
committed by GitHub
10 changed files with 377 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
// Type definitions for next 2.4
// Project: https://github.com/zeit/next.js
// Definitions by: Drew Hays <https://github.com/dru89>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
/// <reference types="node" />
declare module 'next' {
import * as http from 'http';
import * as url from 'url';
type UrlLike = url.UrlObject | url.Url;
interface ServerConfig {
// known keys
webpack?: any;
webpackDevMiddleware?: any;
poweredByHeader?: boolean;
distDir?: string;
assetPrefix?: string;
configOrigin?: string;
useFileSystemPublicRoutes?: boolean;
// and since this is a config, it can take anything else, too.
[key: string]: any;
}
interface ServerOptions {
dir?: string;
dev?: boolean;
staticMarkup?: boolean;
quiet?: boolean;
conf?: ServerConfig;
}
interface Server {
handleRequest(req: http.IncomingMessage, res: http.ServerResponse, parsedUrl?: UrlLike): Promise<void>;
getRequestHandler(): (req: http.IncomingMessage, res: http.ServerResponse, parsedUrl?: UrlLike) => Promise<void>;
prepare(): Promise<void>;
close(): Promise<void>;
defineRoutes(): Promise<void>;
start(): Promise<void>;
run(req: http.IncomingMessage, res: http.ServerResponse, parsedUrl: UrlLike): Promise<void>;
render(req: http.IncomingMessage, res: http.ServerResponse, pathname: string, query: {[key: string]: any}, parsedUrl: UrlLike): Promise<void>;
renderError(err: any, req: http.IncomingMessage, res: http.ServerResponse, pathname: string, query: {[key: string]: any}): Promise<void>;
render404(req: http.IncomingMessage, res: http.ServerResponse, parsedUrl: UrlLike): Promise<void>;
renderToHTML(req: http.IncomingMessage, res: http.ServerResponse, pathname: string, query: {[key: string]: any}): Promise<string>;
renderErrorToHTML(err: any, req: http.IncomingMessage, res: http.ServerResponse, pathname: string, query: {[key: string]: any}): Promise<string>;
serveStatic(req: http.IncomingMessage, res: http.ServerResponse, path: string): Promise<void>;
isServeableUrl(path: string): boolean;
isInternalUrl(req: http.IncomingMessage): boolean;
readBuildId(): string;
handleBuildId(buildId: string, res: http.ServerResponse): boolean;
getCompilationError(page: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<any>;
handleBuildHash(filename: string, hash: string, res: http.ServerResponse): void;
send404(res: http.ServerResponse): void;
}
export default function(options?: ServerOptions): Server;
}
declare module 'next/error' {
import * as React from 'react';
export default class extends React.Component<{statusCode: number}, {}> {}
}
declare module 'next/head' {
import * as React from 'react';
function defaultHead(): JSX.Element[];
export default class extends React.Component<{}, {}> {}
}
declare module 'next/document' {
import * as React from 'react';
interface DocumentProps {
__NEXT_DATA__?: any;
dev?: boolean;
chunks?: string[];
head?: Array<React.ReactElement<any>>;
styles?: Array<React.ReactElement<any>>;
[key: string]: any;
}
class Head extends React.Component<any, {}> {}
class Main extends React.Component<{}, {}> {}
class NextScript extends React.Component<{}, {}> {}
export default class extends React.Component<DocumentProps, {}> {}
}
declare module 'next/link' {
import * as url from 'url';
import * as React from 'react';
type UrlLike = url.UrlObject | url.Url;
interface LinkState {
prefetch?: boolean;
shallow?: boolean;
scroll?: boolean;
replace?: boolean;
onError?(error: any): void;
href?: string | UrlLike;
as?: string | UrlLike;
children: React.ReactElement<any>;
}
export default class extends React.Component<LinkState, {}> {}
}
declare module 'next/dynamic' {
import * as React from 'react';
interface DynamicOptions<TCProps, TLProps> {
loading?: React.ComponentType<TLProps>;
ssr?: boolean;
modules?(props: TCProps & TLProps): { [key: string]: Promise<React.ComponentType<any>> };
render?(props: TCProps & TLProps, modules: { [key: string]: React.ComponentType<any> }): void;
}
class SameLoopPromise<T> extends Promise<T> {
constructor(executor: (resolve: (value?: T) => void, reject: (reason?: any) => void) => void);
setResult(value: T): void;
setError(value: any): void;
runIfNeeded(): void;
}
export default function<TCProps, TLProps>(componentPromise: Promise<React.ComponentType<TCProps>>, options?: DynamicOptions<TCProps, TLProps>): React.ComponentType<TCProps & TLProps>;
}
declare module 'next/router' {
import * as React from 'react';
interface EventChangeOptions {
shallow?: boolean;
[key: string]: any;
}
type RouterCallback = () => void;
interface SingletonRouter {
readyCallbacks: RouterCallback[];
ready(cb: RouterCallback): void;
// router properties
readonly components: { [key: string]: { Component: React.ComponentType<any>, err: any } };
readonly pathname: string;
readonly route: string;
readonly asPath: string;
readonly query: { [key: string]: any };
// router methods
reload(route: string): Promise<void>;
back(): void;
push(url: string, as?: string, options?: EventChangeOptions): Promise<boolean>;
replace(url: string, as?: string, options?: EventChangeOptions): Promise<boolean>;
prefetch(url: string): Promise<React.ComponentType<any>>;
// router events
onAppUpdated?(nextRoute: string): void;
onRouteChangeStart?(url: string): void;
onBeforeHistoryChange?(as: string): void;
onRouteChangeComplete?(url: string): void;
onRouteChangeError?(error: any, url: string): void;
}
const Singleton: SingletonRouter;
export default Singleton;
}
+54
View File
@@ -0,0 +1,54 @@
import createServer from 'next';
import * as http from 'http';
import * as url from 'url';
const defaultServer = createServer();
const server = createServer({
dir: '..',
quiet: true,
conf: {
distDir: './dist',
useFileSystemPublicRoutes: false,
anotherProperty: {
key: true
}
}
});
const voidFunc = () => {};
const stringFunc = (x: string) => x.split('\n');
server.prepare().then(voidFunc);
server.close().then(voidFunc);
server.defineRoutes().then(voidFunc);
server.start().then(voidFunc);
const parsedUrl = url.parse('https://www.example.com');
const handler = server.getRequestHandler();
function handle(req: http.IncomingMessage, res: http.ServerResponse) {
handler(req, res);
handler(req, res, parsedUrl).then(voidFunc);
server.run(req, res, parsedUrl).then(voidFunc);
server.render(req, res, '/path/to/resource', {}, parsedUrl).then(voidFunc);
server.render(req, res, '/path/to/resource', { key: 'value' }, parsedUrl).then(voidFunc);
server.renderError(new Error(), req, res, '/path/to/resource', { key: 'value' }).then(voidFunc);
server.renderError('this can be an error, too!', req, res, '/path/to/resource', { key: 'value' }).then(voidFunc);
server.render404(req, res, parsedUrl).then(voidFunc);
server.renderToHTML(req, res, '/path/to/resource', { foo: 'bar' }).then(x => x.split('\n'));
server.renderErrorToHTML(new Error(), req, res, '/path/to/resource', { foo: 'bar' }).then(x => x.split('\n'));
server.serveStatic(req, res, '/path/to/thing').then(voidFunc);
let b: boolean;
b = server.isServeableUrl('/path/to/thing');
b = server.isInternalUrl(req);
b = server.handleBuildId('{buildId}', res);
const s: string = server.readBuildId();
server.getCompilationError('page', req, res).then(err => err.thisIsAnAny);
server.handleBuildHash('filename', 'hash', res);
server.send404(res);
}
+12
View File
@@ -0,0 +1,12 @@
import Document, * as document from 'next/document';
import * as React from 'react';
const results = (
<Document any="property" should="work" here>
<document.Head some="more" properties>
<meta name="description" content="Head can have children, too!" />
</document.Head>
<document.Main />
<document.NextScript />
</Document>
);
+23
View File
@@ -0,0 +1,23 @@
import dynamic, * as d from 'next/dynamic';
import * as React from 'react';
// typically you'd use this with an esnext-style import() statement, but we'll make do without
interface DynamicComponentProps {
foo: string;
bar: number;
}
async function getComponent() {
return (
(props: DynamicComponentProps) => <div>I'm an async component! {props.foo} {props.bar}</div>
);
}
interface LoadingComponentProps {
baz: boolean;
}
const DynamicComponent = dynamic(getComponent(), {
loading: (props: LoadingComponentProps) => <div>Loading! {props.baz}</div>
});
const jsx = (<DynamicComponent foo='five' bar={5} baz />);
+6
View File
@@ -0,0 +1,6 @@
import * as React from 'react';
import ErrorComponent from 'next/error';
const result = (
<ErrorComponent statusCode={404} />
);
+9
View File
@@ -0,0 +1,9 @@
import Head, * as head from 'next/head';
import * as React from 'react';
const elements: JSX.Element[] = head.defaultHead();
const jsx = (
<Head>
{elements}
</Head>
);
+13
View File
@@ -0,0 +1,13 @@
import Link from 'next/link';
import * as React from 'react';
const links = (
<div>
<Link as="foo" href="https://www.example.com" onError={(e: any) => { console.log("Handled error!", e); }} prefetch replace scroll shallow>
<a>Gotta link to somewhere!</a>
</Link>
<Link>
<a>All props are optional!</a>
</Link>
</div>
);
+50
View File
@@ -0,0 +1,50 @@
import Router, * as r from 'next/router';
import * as React from 'react';
import * as qs from 'querystring';
Router.readyCallbacks.push(() => { console.log("I'll get called when the router initializes."); });
Router.ready(() => { console.log("I'll get called immediately if the router initializes, or when it eventually does."); });
// Access readonly properties of the router.
Object.keys(Router.components).forEach(key => {
const c = Router.components[key];
c.err.isAnAny;
return <c.Component />;
});
function split(routeLike: string) {
routeLike.split('/').forEach(part => {
console.log("path part: ", part);
});
}
split(Router.pathname);
split(Router.asPath);
split(Router.asPath);
const query = `?${qs.stringify(Router.query)}`;
// Assign some callback methods.
Router.onAppUpdated = (nextRoute: string) => console.log(nextRoute);
Router.onRouteChangeStart = (url: string) => console.log("Route is starting to change.", url);
Router.onBeforeHistoryChange = (as: string) => console.log("History hasn't changed yet.", as);
Router.onRouteChangeComplete = (url: string) => console.log("Route chaneg is complete.", url);
Router.onRouteChangeError = (err: any, url: string) => console.log("Route is starting to change.", url, err);
// Call methods on the router itself.
Router.reload('/route').then(() => console.log('route was reloaded'));
Router.back();
Router.push('/route').then((success: boolean) => console.log('route push success: ', success));
Router.push('/route', '/asRoute').then((success: boolean) => console.log('route push success: ', success));
Router.push('/route', '/asRoute', {shallow: false}).then((success: boolean) => console.log('route push success: ', success));
Router.replace('/route').then((success: boolean) => console.log('route replace success: ', success));
Router.replace('/route', '/asRoute').then((success: boolean) => console.log('route replace success: ', success));
Router.replace('/route', '/asRoute', {shallow: false}).then((success: boolean) => console.log('route replace success: ', success));
Router.prefetch('/route').then(Component => {
const element = (<Component />);
});
+31
View File
@@ -0,0 +1,31 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"target": "es6",
"jsx": "react",
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"next-tests.ts",
"test/next-error-tests.tsx",
"test/next-head-tests.tsx",
"test/next-document-tests.tsx",
"test/next-link-tests.tsx",
"test/next-dynamic-tests.tsx",
"test/next-router-tests.tsx"
]
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "dtslint/dt.json",
"rules": {
// All of the different "export default" lines in the index.d.ts
// appear to be triggering this. Remove this when I know of a way
// to declare a default export across multiple package/subpackages.
"strict-export-declare-modifiers": false
}
}