├── docs ├── troubleshooting.md ├── next-steps │ ├── README.md │ ├── measure-type-coverage.md │ ├── add-an-autoformatter.md │ └── keep-your-dependencies-up-to-date.md ├── best-practices │ ├── README.md │ ├── optimize-the-production-build.md │ ├── pick-a-unique-name.md │ ├── do-not-suppress-compilation-errors.md │ ├── make-incremental-builds-fast-for-easy-development.md │ ├── do-not-depend-on-global-variables.md │ └── make-your-public-api-augmentation-friendly.md ├── README.md ├── SUMMARY.md ├── frequently-asked-questions.md └── configuration.md ├── .gitignore ├── .gitbook.yaml ├── .prettierrc ├── .vscode └── extensions.json ├── README.md ├── LICENSE └── .gitbook └── assets └── logo.svg /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/next-steps/README.md: -------------------------------------------------------------------------------- 1 | # Next steps 2 | 3 | -------------------------------------------------------------------------------- /docs/best-practices/README.md: -------------------------------------------------------------------------------- 1 | # Best practices 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .drafts/* 2 | 3 | .vscode/* 4 | !.vscode/extensions.json 5 | -------------------------------------------------------------------------------- /.gitbook.yaml: -------------------------------------------------------------------------------- 1 | root: ./docs 2 | 3 | structure: 4 | readme: README.md 5 | summary: SUMMARY.md 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "proseWrap": "always", 4 | "tabWidth": 2, 5 | "useTabs": false 6 | } 7 | -------------------------------------------------------------------------------- /docs/best-practices/optimize-the-production-build.md: -------------------------------------------------------------------------------- 1 | # Optimize the production build 2 | 3 | Probably the easiest way to build your project is to use [microbundle](https://github.com/developit/microbundle). It will optimize production builds for you as well as provide the `watch` mode for development. 4 | 5 | -------------------------------------------------------------------------------- /docs/next-steps/measure-type-coverage.md: -------------------------------------------------------------------------------- 1 | # Measure type coverage 2 | 3 | Use [type-coverage](https://github.com/plantain-00/type-coverage) to make sure that type density in your codebase doesn't drop in the future. Set a goal \(for example 99%\) and run the tool against your codebase before you commit or push. 4 | 5 | -------------------------------------------------------------------------------- /docs/best-practices/pick-a-unique-name.md: -------------------------------------------------------------------------------- 1 | # Pick a unique name 2 | 3 | Use the [Open Source Project Name Checker](http://ivantomic.com/projects/ospnc/) to check if no package uses it already. It may be a good idea to check for [available domains](https://zeit.co/domains) in case your project gets large and popular. 4 | 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "streetsidesoftware.code-spell-checker", 4 | "EditorConfig.EditorConfig", 5 | "bierner.markdown-checkbox", 6 | "bierner.markdown-preview-github-styles", 7 | "esbenp.prettier-vscode", 8 | "DavidAnson.vscode-markdownlint" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /docs/best-practices/do-not-suppress-compilation-errors.md: -------------------------------------------------------------------------------- 1 | # Do not suppress compilation errors 2 | 3 | Using `// @ts-ignore` comments in your source is a serious code smell. Not only does it hide ugliness, but it can also break your consumers' code when the `--removeComments` compiler flag is turned on, because stripping these comments will uncover compilation errors in your package. 4 | 5 | -------------------------------------------------------------------------------- /docs/best-practices/make-incremental-builds-fast-for-easy-development.md: -------------------------------------------------------------------------------- 1 | # Make incremental builds fast for easy development 2 | 3 | If you are developing a Node.js library, use [ts-node-dev](https://github.com/whitecolor/ts-node-dev) for fast incremental rebuilds. It bundles [ts-node](https://github.com/TypeStrong/ts-node) together with [nodemon](https://github.com/remy/nodemon). It also watches your `tsconfig.json` for changes which makes prototyping easy and fast. 4 | 5 | -------------------------------------------------------------------------------- /docs/next-steps/add-an-autoformatter.md: -------------------------------------------------------------------------------- 1 | # Add an autoformatter 2 | 3 | [Prettier](https://github.com/prettier/prettier) will take care of the formatting for you. Use [tslint-config-prettier](https://github.com/prettier/tslint-config-prettier) or [prettier-tslint](https://github.com/azz/prettier-tslint) to avoid conflicts between TSLint and Prettier. 4 | 5 | Optionally, run Prettier with a pre-commit/pre-push tool. [Learn more](https://prettier.io/docs/en/precommit.html). 6 | 7 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | The objective of this guide is to collect everything you need to successfully publish a library created with TypeScript. 4 | 5 | This includes, but is not limited to: 6 | 7 | * [x] What are the recommended settings 8 | * [x] What are the common pitfalls 9 | * [x] Your pre-launch checklist 10 | 11 | ## Roadmap 12 | 13 | * [ ] Code examples 14 | * [ ] [Project references](https://www.typescriptlang.org/docs/handbook/project-references.html), Lerna and monorepos 15 | * [ ] Test runner configuration 16 | * [ ] Repository badges 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 | 7 | # Create a TypeScript Library 8 | 9 | The objective of this guide is to collect everything you need to successfully publish a library 10 | created with TypeScript. 11 | 12 | This includes: 13 | 14 | - [x] What are the recommended settings 15 | - [x] What are the common pitfalls 16 | - [x] Your pre-launch checklist 17 | 18 | ## Documentation 19 | 20 | This guide is available at [library.typescript.guide](https://library.typescript.guide/). 21 | 22 | ## Roadmap 23 | 24 | - [ ] Code examples 25 | - [ ] [Project references](https://www.typescriptlang.org/docs/handbook/project-references.html), 26 | Lerna and monorepos 27 | - [ ] Test runner configuration 28 | - [ ] Repository badges 29 | 30 | ## Contributing 31 | 32 | Contributions of any kind are welcome. If you feel that something is missing, please open a pull 33 | request or [open an issue](https://github.com/karol-majewski/create-typescript-library/issues/new). 34 | 35 | ## License 36 | 37 | The MIT License. 38 | -------------------------------------------------------------------------------- /docs/best-practices/do-not-depend-on-global-variables.md: -------------------------------------------------------------------------------- 1 | # Do not depend on global variables 2 | 3 | [Depend on an interface](https://en.wikipedia.org/wiki/Dependency_inversion_principle) instead. 4 | 5 | ## Example 1 6 | 7 | If your library is a wrapper for Web Storage, don't call `window.localStorage` directly. 8 | 9 | ### Bad 10 | 11 | When `localStorage` is unavailable \(think Safari Private Mode on iOS\), this function will throw an exception. 12 | 13 | ```typescript 14 | function get(key: string): string | null { 15 | localStorage.get(key); 16 | } 17 | ``` 18 | 19 | ### Good 20 | 21 | Your consumers must bring their own `Storage` — be it `localStorage`, `sessionStorage` or a custom `Storage`. 22 | 23 | ```typescript 24 | function get(key: string, storage: Storage): string | null { 25 | storage.get(key); 26 | } 27 | ``` 28 | 29 | ### Good 30 | 31 | Your consumers _can_ bring their own `Storage` if they want, and `localStorage` is used by default. 32 | 33 | ```typescript 34 | function get(key: string, storage: Storage = localStorage): string | null { 35 | storage.get(key); 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Karol Majewski 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 | -------------------------------------------------------------------------------- /.gitbook/assets/logo.svg: -------------------------------------------------------------------------------- 1 | upArtboard 1 -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Getting started](README.md) 4 | * [Configuration](configuration.md) 5 | * [Best practices](best-practices/README.md) 6 | * [Pick a unique name](best-practices/pick-a-unique-name.md) 7 | * [Optimize the production build](best-practices/optimize-the-production-build.md) 8 | * [Make incremental builds fast for easy development](best-practices/make-incremental-builds-fast-for-easy-development.md) 9 | * [Make your public API augmentation-friendly](best-practices/make-your-public-api-augmentation-friendly.md) 10 | * [Do not depend on global variables](best-practices/do-not-depend-on-global-variables.md) 11 | * [Do not suppress compilation errors](best-practices/do-not-suppress-compilation-errors.md) 12 | * [Next steps](next-steps/README.md) 13 | * [Add an autoformatter](next-steps/add-an-autoformatter.md) 14 | * [Measure type coverage](next-steps/measure-type-coverage.md) 15 | * [Keep your dependencies up to date](next-steps/keep-your-dependencies-up-to-date.md) 16 | * [FAQ](frequently-asked-questions.md) 17 | 18 | ## See also 19 | 20 | * [Starting an Open Source Project](https://opensource.guide/starting-a-project/) 21 | * [How to promote your GitHub project](https://hackernoon.com/how-to-promote-your-github-project-1b39a7eee841) 22 | 23 | -------------------------------------------------------------------------------- /docs/frequently-asked-questions.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## Should I transpile my code to ES5 in 2019? 4 | 5 | Excellent question! The best way out of this problem is to simultaneously ship two versions of your project: a CommonJS module \(legacy\) and a modern ECMAScript one. That's what [microbundle](https://github.com/developit/microbundle) can do for you out of the box. 6 | 7 | Read more: [Deploying ES2015+ Code in Production Today](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/). 8 | 9 | ## My library is a React component. Is there anything I need to know? 10 | 11 | React components are just JavaScript functions \(or classes\), so there isn't anything special about them. However, if your component is a [Higher-Order Component](https://reactjs.org/docs/higher-order-components.html), you can make the developer experience better by doing the following: 12 | 13 | * Export the interface describing the props supplied by your HOC 14 | * Export the interface telling your user what props must be supplied 15 | * If your HOC accepts a React component and returns a React component, the props accepted by the 16 | 17 | created component should not include the props already supplied by your HOC 18 | 19 | * Expose the wrapped component by using a static property or 20 | 21 | [`forwardRef`](https://reactjs.org/docs/forwarding-refs.html) 22 | 23 | ## I don't want to rewrite my library. I just want to add type definitions to it. 24 | 25 | It's best to submit your type definitions to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped). 26 | 27 | -------------------------------------------------------------------------------- /docs/next-steps/keep-your-dependencies-up-to-date.md: -------------------------------------------------------------------------------- 1 | # Keep your dependencies up to date 2 | 3 | JavaScript ecosystem is know for its frequent updates. It's even more true for TypeScript, because when the source code of your dependency and its type definitions live in two different places \(DefinitelyTyped\), you can expect them to evolve asynchronously. It's important to make sure _your_ dependencies are well-defined and deterministic in their behavior. 4 | 5 | ## Saving exact versions 6 | 7 | One solution to this problem is to save [exact versions](https://docs.npmjs.com/cli/install) of your dependencies. 8 | 9 | ```bash 10 | npm install --save-exact 11 | ``` 12 | 13 | This will opt-out of the default `npm install` behavior which takes semantic versioning into account. While it makes your builds deterministic, it has a severe disadvantage: it makes it more difficult to reuse already installed packages, since they will rarely match the same version. 14 | 15 | ## Automatic updates 16 | 17 | A better solution is to have a tool like [Greenkeeper](https://greenkeeper.io/) or [Dependabot](https://dependabot.com/) scan the npm registry for updates and open a pull request when they are found. When a dependency from within the desired version range is going to break your build, a pull request with the details will be created for you. 18 | 19 | ## Manual updates 20 | 21 | Greenkeeper and Dependabot are free for open source projects. If your project is private and you are ale looking for a free solution, you can create an npm script running `npx npm-check`. 22 | 23 | In your `package.json`, add a script like this one: 24 | 25 | ```javascript 26 | { 27 | "scripts": { 28 | "dependencies:update": "npx npm-check --update" 29 | } 30 | } 31 | ``` 32 | 33 | Running `npm run dependencies:update` will open an interactive panel in your terminal. Cherry-pick the packages you are interested in and hit Enter to confirm. 34 | 35 | -------------------------------------------------------------------------------- /docs/best-practices/make-your-public-api-augmentation-friendly.md: -------------------------------------------------------------------------------- 1 | # Make your public API augmentation-friendly 2 | 3 | Once a package is published, its type definitions are often [augmented](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) by the consumers. There are a few reasons for that: 4 | 5 | * **Type definitions are not precise enough.** If a public API makes use of broad types \(like `any` or `{}`\), not only does it defeat the purpose of using TypeScript — but it may also conflict with TSLint rules like [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/), forcing the consumer to use a type assertion. 6 | * **A new version of TypeScript was released in the meantime.** TypeScript has a relatively short release cycle. When a new feature lands, it can used to get more type safety out of your code. 7 | * **Functionality was added to your library, but its type definitions do not reflect that.** That's often the case when the source code is at least partially created with JavaScript. 8 | 9 | By allowing your consumers to augment the type definitions bundled with your package, you can create a safe environment in which everyone can get what they want without being dependent on each other. 10 | 11 | What does it mean for a pubic interface to be augmentation friendly? 12 | 13 | * Functions and methods are described with interfaces \(_call signatures_\), not function types. This 14 | 15 | makes it possible to add overload definitions for them. 16 | 17 | * Type definitions are built of small definitions composed together. It makes it easier to import 18 | 19 | just a small subset of a type definition and reuse it \(instead of having to decompose a big 20 | 21 | definition yourself\). 22 | 23 | * If it depends on third party types, ECMAScript import syntax is used instead of 24 | 25 | [triple-slash directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html). 26 | 27 | -------------------------------------------------------------------------------- /docs/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ## Repository contents 4 | 5 | * [ ] Your package has a README. Read more at [makeareadme.com](https://www.makeareadme.com/). 6 | * [ ] Your package has a license. Not sure which should you choose? Go to [choosealicense.com](https://choosealicense.com/). 7 | 8 | ## `package.json` 9 | 10 | Generate the file by running `npm init` or `yarn init`. Once it's done, make sure: 11 | 12 | * [ ] The required fields are present \(`name`, `main`, `version`\) 13 | * [ ] The `main` field points to an existing file 14 | * [ ] The `types` \(or `typings`\) field points to a type declaration \(`*.d.ts`\) file 15 | * [ ] The `typesVersions` field, if used, follows the 16 | 17 | [correct syntax](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html) 18 | 19 | * [ ] The `files` field includes your JavaScript artifacts as well as your declaration files 20 | * [ ] A corresponding lockfile \(either `package-lock.json` or `yarn.lock`\) is generated and committed to the repository 21 | 22 | Read more about `package.json` in the [official documentation](https://docs.npmjs.com/files/package.json) and [here](https://github.com/stereobooster/package.json). 23 | 24 | ## `tsconfig.json` 25 | 26 | It's best to create your `tsconfig.json` by running `tsc --init` in your terminal. A configuration file generated this way makes the decisions explicit, and it also provides comments useful for any collaborators not familiar with TypeScript. 27 | 28 | Once that's done, make sure that: 29 | 30 | * [ ] `sourceMap` is set to `true` 31 | * [ ] `declaration` is set to `true` 32 | * [ ] `declarationMap` is set to `true` 33 | * [ ] `removeComments` is set to `false` 34 | * [ ] `strict` is set to `true` 35 | * [ ] `allowSyntheticDefaultImports` is set to `true` 36 | * [ ] `moduleResolution` is set to `"node"` 37 | * [ ] `esModuleInterop` is set to `true` 38 | 39 | Read more about [the options available in `tsconfig.json`.](https://www.typescriptlang.org/docs/handbook/compiler-options.html) 40 | 41 | --------------------------------------------------------------------------------