Skip to content

Commit

Permalink
Update TypeScript recipe to remove ts-node recommendation (#3192)
Browse files Browse the repository at this point in the history
* Update typescript recipe to use the tsx loader;
* Remove ts-node references; strongly advocate @ava/typescript; general instructions for setting up custom loaders

---------

Co-authored-by: Mark Wubben <mark@novemberborn.net>
  • Loading branch information
ondreian and novemberborn committed May 21, 2023
1 parent 5bf01a3 commit 49e5582
Showing 1 changed file with 17 additions and 119 deletions.
136 changes: 17 additions & 119 deletions docs/recipes/typescript.md
Expand Up @@ -8,92 +8,33 @@ This guide assumes you've already set up TypeScript for your project. Note that

## Enabling AVA's support for TypeScript test files

### With precompile step
Broadly speaking, there are two ways to run tests written in TypeScript:

Out of the box AVA does not load TypeScript test files. You can use our [`@ava/typescript`] package, which is designed to work for projects that precompile TypeScript using the `tsc` command. Please see [`@ava/typescript`] for setup instructions.
1. Build first, then test against the build output
2. Configure loaders which build test files as they're loaded

### Using `ts-node`
**The first option is the most reliable since it doesn't rely on experimental Node.js features.** You can use our [`@ava/typescript`] package, which is designed to work for projects that precompile TypeScript using the `tsc` command. Please see [`@ava/typescript`] for setup instructions. **This package also sets up the various TypeScript file extensions for you.**

You can use [`ts-node`] to do live testing without transpiling. This can be especially helpful when you're using a bundler. Be sure to install the required dev dependencies:
**You can use loaders, but you're largely on your own. [Please post questions to our Discussions forum if you're stuck](https://github.com/avajs/ava/discussions/categories/q-a).**

`npm install --save-dev typescript ts-node`
There are two components to a setup like this:

The required setup depends on the type of your package:
1. [Make sure AVA recognizes the extensions of your TypeScript files](../06-configuration.md#configuring-module-formats)
2. Install the loader [through `nodeArguments`](../06-configuration.md#node-arguments)

1. [for packages with type "module"](#for-packages-with-type-module)
2. [for packages without type "module"](#for-packages-without-type-module)

#### For packages with type `module`

If your `package.json` has `"type": "module"`, then this is the AVA configuration you need:

`package.json`:

```json
{
"ava": {
"extensions": {
"ts": "module"
},
"nodeArguments": [
"--loader=ts-node/esm"
]
}
}
```

You also need to have this in your `tsconfig.json`:

```json
{
"compilerOptions": {
"module": "ES2020",
"moduleResolution": "node"
}
}
```

Remember that, by default, ES modules require you to specify the file extension and TypeScript outputs `.js` files, so you have to write your imports to load from `.js` files not `.ts`.

If this is not to your liking there is an _experimental_ option in Node.js that you might want to use. You can add it to the `nodeArguments` array in the AVA configuration so it applies to your test runs: [`--experimental-specifier-resolution=node`](https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm).

#### For packages without type "module"

If your `package.json` does not have `"type": "module"`, then this is the AVA configuration you need:

`package.json`:

```json
{
"ava": {
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
}
}
```

It's worth noting that with this configuration, tests will fail if there are TypeScript build errors. Suppose you want to test while ignoring these errors. In that case, you can use `ts-node/register/transpile-only` instead of `ts-node/register` or add an environment variable for ts-node to log errors to stderr instead of throwing an exception.
[`tsx`](https://github.com/esbuild-kit/tsx) may be the best loader available. The setup, assuming your TypeScript config outputs ES modules, would look like this:

`package.json`:

```json
{
"ava": {
"extensions": [
"ts"
],
"environmentVariables": {
"TS_NODE_LOG_ERROR": "true"
},
"require": [
"ts-node/register"
]
}
}
"ava": {
"extensions": {
"ts": "module"
},
"nodeArguments": [
"--loader=tsx"
]
}
```

## Writing tests
Expand Down Expand Up @@ -236,47 +177,4 @@ test('throwsAsync', async t => {

Note that, despite the typing, the assertion returns `undefined` if it fails. Typing the assertions as returning `Error | undefined` didn't seem like the pragmatic choice.

### Using module path mapping

`ts-node` [does not support module path mapping](https://github.com/TypeStrong/ts-node/issues/138), however you can use [`tsconfig-paths`](https://github.com/dividab/tsconfig-paths#readme).

Once installed, add the `tsconfig-paths/register` entry to the `require` section of AVA's config:

`package.json`:

```json
{
"ava": {
"extensions": [
"ts"
],
"require": [
"ts-node/register",
"tsconfig-paths/register"
]
}
}
```

Then you can start using module aliases:

`tsconfig.json`:
```json
{
"baseUrl": ".",
"paths": {
"@helpers/*": ["helpers/*"]
}
}
```

Test:

```ts
import myHelper from '@helpers/myHelper';

// Rest of the file
```

[`@ava/typescript`]: https://github.com/avajs/typescript
[`ts-node`]: https://www.npmjs.com/package/ts-node

0 comments on commit 49e5582

Please sign in to comment.