๐Ÿšง TSNew is experimental. Avoid usage unless you're providing feedback. ๐Ÿšง
Getting Started

What is TSNew?

TSNew is a strongly typed templating system to generate feature code.

It makes teams more efficient while enforcing existing project patterns and decisions.

Install the package

Install the tsnew package (opens in a new tab) as a dev dependency with your preferred package manager:


npm install tsnew --save-dev

Why not a global installation?

Installing as a dev dependency keeps a locked version scoped to your project, and provides the template API to define templates. If each developer installs TSNew globally, then they may run into issues across projects.

Create a template

Run the npx tsnew CLI to set up a basic template:


npx tsnew

Example Run


โ”Œ ๐Ÿ†• tsnew start
โ”‚
โ–ฒ You don't have any templates.
โ”‚
โ— Let's create your first one!
โ”‚
โ—‡ What is the name of this template?
โ”‚ component
โ”‚
โ—‡ Created .tsnew/templates/component
โ”‚
โ”” ๐Ÿ†• tsnew end
You can update your new templates here:
.tsnew
โ””โ”€โ”ฌ templates
โ””โ”€โ”€ component
After that, you can run your template:
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ $ npx tsnew component โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Run the template

You can view and run available templates now:


npx tsnew

If you don't want to select a template each time, you can also run a template right away:


npx tsnew <name>

For example, you can run npx tsnew component if you have a component template.

Customize your templates

The template API is simple yet powerful. We'll now walk through a more real world example.

Let's say we have the following template files:

input.ts
component.template.ts
test.template.ts
readme.template.ts

import type { Input } from 'tsnew';
/**
* Prompt CLI for input data to use in templates.
*/
export const input = {
name: {
type: 'text',
message: 'What is the name of this component?',
},
} satisfies Input;

It would be tedious to keep prompting for the same input in each template, so the input is shared across multiple templates via imports. The satisfies keyword (opens in a new tab) is necessary because we want to retain the actual object type of the input. This way, when you attempt to use input.name it is known to be a valid string property.

Alright, let's run our component template:


npx tsnew component

For this example, we'll create a Button component:


โ”Œ ๐Ÿ†• tsnew start
โ”‚
โ—‡ What is the name of this component?
โ”‚ Button
โ”‚
โ— Created components/Button/README.md
โ”‚
โ— Created components/Button/Button.tsx
โ”‚
โ— Created components/Button/Button.test.tsx
โ”‚
โ”” ๐Ÿ†• tsnew end

Nice! The following files were created:

Button.tsx
Button.test.tsx
README.md

export function Button() {
return <p>I am a component!</p>;
}