[Wouter] Add types for v2 (#36330)

This commit is contained in:
Alexander Tolkunov
2019-06-21 03:42:32 +03:00
committed by Daniel Rosenwasser
parent d88107bef1
commit 498d415b56
10 changed files with 274 additions and 51 deletions

View File

@@ -1,31 +1,38 @@
// Type definitions for wouter 1.2
// Type definitions for wouter 2.0
// Project: https://github.com/molefrog/wouter#readme
// Definitions by: Tolkunov Alexander <https://github.com/StrayFromThePath>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import * as React from 'react';
import {
FunctionComponent,
ComponentType,
ReactElement,
ReactNode
} from "react";
export type Params = { [paramName: string]: string } | null;
export type Path = string;
export type PushCallback = (to: string) => void;
export type LocationTuple = [Path, PushCallback];
export type Match = [boolean, Params];
export type MatcherFn = (pattern: string, path: Path) => Match;
export interface RouteProps {
children?: ((params: Params) => React.ReactNode) | React.ReactNode;
children?: ((params: Params) => ReactNode) | ReactNode;
path: Path;
component?: React.ComponentType<any>;
component?: ComponentType<any>;
match?: boolean;
}
export const Route: React.FunctionComponent<RouteProps>;
export const Route: FunctionComponent<RouteProps>;
export interface LinkProps {
to?: string;
href?: string;
children: React.ReactElement;
children: ReactElement;
onClick?: () => void;
}
export const Link: React.FunctionComponent<LinkProps>;
export const Link: FunctionComponent<LinkProps>;
export interface RedirectProps {
to?: string;
@@ -35,24 +42,22 @@ export const Redirect: React.FunctionComponent<RedirectProps>;
export interface SwitchProps {
location?: string;
children: Array<React.ReactElement<RouteProps>>;
}
export const Switch: React.FunctionComponent<SwitchProps>;
export interface History {
path: () => Path;
push: PushCallback;
subscribe: (cb: PushCallback) => () => void;
children: Array<ReactElement<RouteProps>>;
}
export const Switch: FunctionComponent<SwitchProps>;
export interface RouterProps {
history: History;
matcher: (pattern: string, path: Path) => Match;
hook: () => LocationTuple;
matcher: MatcherFn;
}
export const Router: React.FunctionComponent<Partial<RouterProps>>;
export const Router: FunctionComponent<
Partial<RouterProps> & {
children: ReactElement | ReactElement[];
}
>;
export function useRouter(): RouterProps;
export function useRoute(pattern: string): Match;
export function useLocation(): [Path, PushCallback];
export function useLocation(): LocationTuple;

8
types/wouter/matcher.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import { MatcherFn } from "./index";
export default function makeMatcher(
makeRegexpFn?: (
pattern: string,
keys?: Array<{ name: string | number }>
) => RegExp
): MatcherFn;

7
types/wouter/static-location.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import { Path } from "./index";
declare function staticLocationHook(
path?: Path
): () => [Path, (x: Path) => Path];
export = staticLocationHook;

View File

@@ -16,10 +16,14 @@
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"strictFunctionTypes": true
"strictFunctionTypes": true,
"allowSyntheticDefaultImports": true
},
"files": [
"index.d.ts",
"use-location.d.ts",
"static-location.d.ts",
"matcher.d.ts",
"wouter-tests.tsx"
]
}

3
types/wouter/use-location.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
import { LocationTuple } from "./index";
export default function useLocation(): LocationTuple;

58
types/wouter/v1/index.d.ts vendored Normal file
View File

@@ -0,0 +1,58 @@
// Type definitions for wouter 1.2
// Project: https://github.com/molefrog/wouter#readme
// Definitions by: Tolkunov Alexander <https://github.com/StrayFromThePath>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import * as React from 'react';
export type Params = { [paramName: string]: string } | null;
export type Path = string;
export type PushCallback = (to: string) => void;
export type Match = [boolean, Params];
export interface RouteProps {
children?: ((params: Params) => React.ReactNode) | React.ReactNode;
path: Path;
component?: React.ComponentType<any>;
match?: boolean;
}
export const Route: React.FunctionComponent<RouteProps>;
export interface LinkProps {
to?: string;
href?: string;
children: React.ReactElement;
onClick?: () => void;
}
export const Link: React.FunctionComponent<LinkProps>;
export interface RedirectProps {
to?: string;
href?: string;
}
export const Redirect: React.FunctionComponent<RedirectProps>;
export interface SwitchProps {
location?: string;
children: Array<React.ReactElement<RouteProps>>;
}
export const Switch: React.FunctionComponent<SwitchProps>;
export interface History {
path: () => Path;
push: PushCallback;
subscribe: (cb: PushCallback) => () => void;
}
export interface RouterProps {
history: History;
matcher: (pattern: string, path: Path) => Match;
}
export const Router: React.FunctionComponent<Partial<RouterProps>>;
export function useRouter(): RouterProps;
export function useRoute(pattern: string): Match;
export function useLocation(): [Path, PushCallback];

View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../../",
"typeRoots": [
"../../"
],
"types": [],
"paths": {
"wouter": [
"wouter/v1"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"strictFunctionTypes": true
},
"files": [
"index.d.ts",
"wouter-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@@ -0,0 +1,78 @@
import * as React from 'react';
import {
Router,
Route,
Link,
Switch,
useRouter,
useRoute,
useLocation,
Redirect,
} from 'wouter';
const Inbox = () => <h1>Inbox</h1>;
const BaseTest = () => (
<div className="app">
<Link href="/users/alex">
<a className="link">Profile</a>
</Link>
<Link to="/about">
<a className="link">About Us</a>
</Link>
<Link href="/inbox" onClick={() => console.log('navigated to /inbox')}>
<a className="link">Inbox</a>
</Link>
<Router>
<Route path="/about">About Us</Route>
<Route path="/users/:name">
{(params) => <div>Hello, {params && params.name}!</div>}
</Route>
<Route path="/inbox" component={Inbox} />
</Router>
</div>
);
const SwitchTest = () => (
<Switch>
<Route path="/a">A</Route>
<Route path="/b">B</Route>
<Route path="/c">C</Route>
</Switch>
);
const UseRouteTest = () => {
const [match, params] = useRoute('/users/:name');
if (!match) return null;
return <div>Welcome, {params && params.name}!</div>;
};
const UseRouterTest = () => {
const {history, matcher} = useRouter();
const [path] = useLocation();
const [match, params] = matcher("/users/:name", path);
if (!match) return null;
return (
<div>
<div>Your name is {params && params.name}</div>
<div onClick={() => history.push('/orders')}>Orders</div>
</div>
);
};
const useLocationTest = () => {
const [location, navigate] = useLocation();
return (
<div>
<div>Current location: {location}</div>
<div onClick={() => navigate('/home')}>Home</div>
</div>
);
};
<Redirect to="/users" />;

View File

@@ -1,14 +1,19 @@
import * as React from 'react';
import * as React from "react";
import * as express from "express";
import { renderToString } from "react-dom/server";
import {
Router,
Route,
Link,
Switch,
Redirect,
useRouter,
useRoute,
useLocation,
Redirect,
} from 'wouter';
Path,
Params
} from "wouter";
import useLocation from "wouter/use-location";
import staticLocationHook = require("wouter/static-location");
const Inbox = () => <h1>Inbox</h1>;
const BaseTest = () => (
@@ -19,39 +24,27 @@ const BaseTest = () => (
<Link to="/about">
<a className="link">About Us</a>
</Link>
<Link href="/inbox" onClick={() => console.log('navigated to /inbox')}>
<Link href="/inbox" onClick={() => console.log("navigated to /inbox")}>
<a className="link">Inbox</a>
</Link>
<Router>
<Route path="/about">About Us</Route>
<Route path="/users/:name">
{(params) => <div>Hello, {params && params.name}!</div>}
</Route>
<Route path="/inbox" component={Inbox} />
<Switch>
<Route path="/about">About Us</Route>
<Route path="/users/:name">
{params => <div>Hello, {params && params.name}!</div>}
</Route>
<Route path="/inbox" component={Inbox} />
</Switch>
</Router>
</div>
);
const SwitchTest = () => (
<Switch>
<Route path="/a">A</Route>
<Route path="/b">B</Route>
<Route path="/c">C</Route>
</Switch>
);
const UseRouteTest = () => {
const [match, params] = useRoute('/users/:name');
if (!match) return null;
return <div>Welcome, {params && params.name}!</div>;
};
<Redirect to="/users" />;
const UseRouterTest = () => {
const {history, matcher} = useRouter();
const [path] = useLocation();
const { hook, matcher } = useRouter();
const [path, push] = hook();
const [match, params] = matcher("/users/:name", path);
if (!match) return null;
@@ -59,20 +52,56 @@ const UseRouterTest = () => {
return (
<div>
<div>Your name is {params && params.name}</div>
<div onClick={() => history.push('/orders')}>Orders</div>
<div onClick={() => push("/orders")}>Orders</div>
</div>
);
};
const UseRouteTest = () => {
const [match, params] = useRoute("/users/:name");
if (!match) return null;
return <div>Welcome, {params && params.name}!</div>;
};
const useLocationTest = () => {
const [location, navigate] = useLocation();
const [location, setLocation] = useLocation();
return (
<div>
<div>Current location: {location}</div>
<div onClick={() => navigate('/home')}>Home</div>
<div onClick={() => setLocation("/home")}>Home</div>
</div>
);
};
<Redirect to="/users" />;
/* staticLocationHook Test */
const app = express();
app.get("*", (req, res) => {
const html = renderToString(
<Router hook={staticLocationHook(req.path)}>
<Route path="/a">A</Route>
<Route path="/b">B</Route>
</Router>
);
res.status(200).send(html);
});
/* customMatcher Test */
const customMatcher = (pattern: string, path: Path): [boolean, Params] => {
const reversed = path
.replace(/^\//, "")
.split("")
.reverse()
.join("");
return [pattern.replace(/^\//, "") === reversed, {}];
};
const customMatcherTest = () => (
<Router matcher={customMatcher}>
<Route path="/a">A</Route>
</Router>
);