├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── coverage.svg
├── jestconfig.json
├── logo.svg
├── package.json
├── src
├── __tests__
│ └── sample.ts
├── example.tsx
└── index.ts
├── tsconfig.json
├── tslint.json
├── yarn-error.log
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | **/.DS_Store
3 | node_modules
4 | /lib
5 | /coverage
6 | .vscode
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "trailingComma": "all",
4 | "singleQuote": true
5 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Colin McDonnell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
nxtk
2 |
3 | TypeScript utilities for Next.js
4 |
5 |
6 | # Installation
7 |
8 | To install the latest version:
9 |
10 | ```sh
11 | npm install --save nxtk
12 | ```
13 |
14 | ```sh
15 | yarn add nxtk
16 | ```
17 |
18 | ⚠️ Requires TypeScript 3.2+ and `"strictNullChecks": true` to work properly!
19 |
20 | ## Importing
21 |
22 | ```tsx
23 | import { nxtk } from 'nxtk';
24 | ```
25 |
26 | ## `nxtk.fetch`
27 |
28 | This utility reduces the boilerplate required to implement pages with data fetching. It uses type inference to detect the return type of `getStaticProps`, `getServerSideProps`, or both. Then it merges the types so you can trivially add strong typing to your component props.
29 |
30 | ### Defining fetch functions
31 |
32 | ```tsx
33 | // pages/yourpage.tsx
34 |
35 | import React from 'react';
36 | import { nxtk } from 'nxtk';
37 |
38 | const Fetcher = nxtk.fetch({
39 | async server(ctx) {
40 | // ctx = GetServerSidePropsContext
41 | const props = { serverSideProp: 'Hello' };
42 | return { props };
43 | },
44 | async static(ctx) {
45 | // ctx = GetStaticPropsContext
46 | const props = { staticProp: 'World' };
47 | return { props };
48 | },
49 | });
50 | ```
51 |
52 | The `ctx` inputs are automatically typed for you.
53 |
54 |
87 |
88 |
89 |
90 | After creating your "fetcher", export its `getServerSideProps` and `getStaticProps` properties so Next.js can access them.
91 |
92 | ```tsx
93 | export const getServerSideProps = Fetcher.getServerSideProps;
94 | export const getStaticProps = Fetcher.getStaticProps;
95 | ```
96 |
97 | ### Inferring prop types!
98 |
99 | The best part: `nxtk` automatically **infers** the return types of your fetcher functions and **merges** them together. So you can properly type your page components:
100 |
101 | ```tsx
102 | type InferredProps = typeof Fetcher['props']; // { serverSideProp: string; staticProp: string };
103 |
104 | export default function Home(props: InferredProps) {
105 | props;
106 | return (
107 |
108 |
{`${props.serverSideProp} ${props.staticProp}`}
109 |
110 | );
111 | }
112 | ```
113 |
114 | As you can see, the return type of `getServerSideProps` (`{ serverSideProp: string}`) and `getStaticProps` (`{ staticProp: string }`) are inferred and merged into `{ serverSideProp: string; staticProp: string }`. You can access this typing with `typeof Fetcher['props']`.
115 |
116 | This may not look like much with a simple example, but imagine you are doing a serious of complex database queries using a type-safe ORM like TypeORM or Prisma. No matter how compicated your fetching logic gets, `nxtk` can infer it. No need to keep your component `props` in sync with your fetching logic!
117 |
118 | ### Full example
119 |
120 | A full sample page is available at [https://github.com/vriad/nxtk/blob/master/src/example.tsx](https://github.com/vriad/nxtk/blob/master/src/example.tsx).
121 |
122 | ## `nxtk.api`
123 |
124 | This is a helper function for defining API routes.
125 |
126 | ```tsx
127 | // /api/hello.ts
128 | import { nxtk } from 'nxtk';
129 |
130 | export default nxtk.api((req, res) => {
131 | if (req.method !== 'POST') return res.status(200).json({ name: 'unsupported' });
132 | res.status(200).json({ message: 'yay post!' });
133 | });
134 | ```
135 |
136 | ## `nxtk.???`
137 |
138 | If you have any other suggestions of how nxtk could make using Next.js and TypeScript more painless, create an issue! I hope to expand the scope of `nxtk` wherever pain points exist.
139 |
140 | Created by [@vriad](https://twitter.com/vriad)
141 | MIT License
142 |
--------------------------------------------------------------------------------
/coverage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/jestconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "transform": {
3 | "^.+\\.(t|j)sx?$": "ts-jest"
4 | },
5 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
6 | "moduleFileExtensions": [
7 | "ts",
8 | "tsx",
9 | "js",
10 | "jsx",
11 | "json",
12 | "node"
13 | ],
14 | "coverageReporters": [
15 | "json-summary",
16 | "text",
17 | "lcov"
18 | ]
19 | }
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nxtk",
3 | "version": "0.4.0",
4 | "description": "A project template for TypeScript npm packages",
5 | "main": "./lib/src/index.js",
6 | "types": "./lib/src/index.d.ts",
7 | "files": [
8 | "lib"
9 | ],
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/vriad/nxtk"
13 | },
14 | "author": "Colin McDonnell ",
15 | "license": "MIT",
16 | "sideEffects": false,
17 | "bugs": {
18 | "url": "https://github.com/vriad/nxtk/issues"
19 | },
20 | "scripts": {
21 | "clean": "rm -rf lib/*",
22 | "build": "npm run clean && tsc"
23 | },
24 | "homepage": "https://github.com/vriad/nxtk",
25 | "dependencies": {},
26 | "tags": [],
27 | "keywords": [],
28 | "devDependencies": {
29 | "@types/jest": "^25.1.4",
30 | "@types/react": "^16.9.44",
31 | "jest": "^25.1.0",
32 | "make-coverage-badge": "^1.2.0",
33 | "next": "^10.0.3",
34 | "nodemon": "^2.0.2",
35 | "prettier": "^1.19.1",
36 | "react": "^16.13.1",
37 | "react-dom": "^16.13.1",
38 | "ts-jest": "^25.2.1",
39 | "tslint": "^6.1.0",
40 | "tslint-config-prettier": "^1.18.0",
41 | "typescript": "3.2"
42 | },
43 | "peerDependencies": {
44 | "next": "^10"
45 | }
46 | }
--------------------------------------------------------------------------------
/src/__tests__/sample.ts:
--------------------------------------------------------------------------------
1 | test('passing test', () => {
2 | console.log('passes!');
3 | });
4 |
5 | test('failing test', () => {
6 | throw new Error('fails!');
7 | });
8 |
9 | test('expect example', () => {
10 | expect(5).toEqual(6); // fails
11 | });
12 |
--------------------------------------------------------------------------------
/src/example.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { nxtk } from '.';
3 |
4 | const Fetcher = nxtk.fetch({
5 | async server(_ctx) {
6 | return { props: { greeting: 'Hello' } };
7 | },
8 | async static(_ctx) {
9 | return { props: { subject: 'World' } };
10 | },
11 | });
12 |
13 | export const getServerSideProps = Fetcher.getServerSideProps;
14 | export const getStaticProps = Fetcher.getStaticProps;
15 |
16 | export default function Home(props: typeof Fetcher['props']) {
17 | return