What’s New
TSTyche 4

Release Notes

This page lists breaking changes and notable new features. Please be sure to read the release notes before upgrading from previous version.

The detailed changelog can be found in TSTyche repository on GitHub (opens in a new tab).

TSTyche 4.0

TSTyche 4.0 ships with the new .toBeApplicable, .toBeCallableWith() and .toBeConstructableWith() matchers, support for template test files, enhanced protection against accidental any or never types and stricter default compiler options.

Keep in mind that TSTyche 4.0 is still in beta. More breaking changes may be introduced before the stable version is released. To install the latest beta version, use the next distribution tag:

npm add -D tstyche@next

Requirements

The minimum required Node.js version is 20.9. It is recommended to use the latest Long Term Support (LTS) release.

Matchers

Breaking! The deprecated .toMatch() matcher is removed.

Breaking! All primitive type matchers like .toBeString() or .toBeNumber() are removed. Use .toBe() instead:

import { expect } from "tstyche";
 
- expect<string>().type.toBeString();
+ expect<string>().type.toBe<string>();
 
- expect<number>().type.toBeNumber();
+ expect<number>().type.toBe<number>();

.toBeApplicable

The new .toBeApplicable matcher checks if the decorator function can be applied to a class or a class member.

Differently from other matchers, .toBeApplicable must be used as a decorator:

import { expect, test } from "tstyche";
 
function bind<This, Value extends (this: This, ...args: any) => any>(
  target: Value,
  context: ClassMethodDecoratorContext<This, Value>,
) {
  // ...
}
 
test("bind", () => {
  class Fixture {
    #name: string;
 
    constructor(name: string) {
      this.#name = name;
    }
 
    @(expect(bind).type.toBeApplicable) // <-- and here it is!
    toString() {
      return `Hello, my name is ${this.#name}.`;
    }
  }
});

.toBeCallableWith()

The new .toBeCallableWith() matcher checks if a function is callable with the given arguments.

import { expect, test } from "tstyche";
 
function isSameLength<T extends { length: number }>(a: T, b: T) {
  return a.length === b.length;
}
 
test("isSameLength", () => {
  expect(isSameLength([1, 2], [1, 2, 3])).type.toBe<boolean>();
  expect(isSameLength("one", "two")).type.toBe<boolean>();
 
  expect(isSameLength).type.not.toBeCallableWith(1, 2);
  expect(isSameLength).type.not.toBeCallableWith("zero", [123]);
 
  expect(isSameLength<string | Array<number>>).type.toBeCallableWith("zero", [123]);
});

.toBeConstructableWith()

The new .toBeConstructableWith() matcher checks if a class is constructable with the given arguments.

import { expect, test } from "tstyche";
 
class Pair<T> {
  left: T;
  right: T;
 
  constructor(left: T, right: T) {
    this.left = left;
    this.right = right;
  }
}
 
test("Pair", () => {
  expect(Pair).type.toBeConstructableWith("sun", "moon");
  expect(Pair).type.toBeConstructableWith(true, false);
 
  expect(Pair).type.not.toBeConstructableWith("five", 10);
  expect(Pair<number | string>).type.toBeConstructableWith("five", 10);
 
  expect(Pair).type.not.toBeConstructableWith();
  expect(Pair).type.not.toBeConstructableWith("nope");
});

Template Test Files

The template test files allow generating tests using a template and data table.

To mark a test file as a template, add the // @tstyche-template directive as its first line. When the directive is found, the default export of a file is interpreted as a type test text.

For example, the following:

// @tstyche-template
 
let testText = `import { expect, test } from "tstyche";
`;
 
for (const source of ["string", "number"]) {
  testText += `test("is ${source} a string?", () => {
  expect<${source}>().type.toBe<string>();
});
`;
}
 
export default testText;

is interpreted as:

import { expect, test } from "tstyche";
test("is string a string?", () => {
  expect<string>().type.toBe<string>();
});
test("is number a string?", () => {
  expect<number>().type.toBe<string>();
});

To learn more, see the Template Test Files page.

Thanks to @nikelborm (opens in a new tab) for the idea!

Configuration

checkSourceFiles

The checkSourceFiles configuration option is enabled by default.

rejectAnyType

The rejectAnyType configuration option is enabled by default.

rejectNeverType

The rejectNeverType configuration option is enabled by default.

target

Breaking! The lowest support TypeScript versions is now 4.7.

Command Line

--fetch

--fetch is the new name of --install.

Compiler Options

If your project does not have a TSConfig file, the default compiler options now are much more strict:

{
  "allowImportingTsExtensions": true, // not set for TypeScript 4.x
  "allowJs": true,
  "checkJs": true,
  "exactOptionalPropertyTypes": true,
  "jsx": "preserve",
  "module": "nodenext",
  "moduleResolution": "nodenext",
  "noUncheckedIndexedAccess": true,
  "resolveJsonModule": true,
  "strict": true,
  "target": "esnext",
  "verbatimModuleSyntax": true // not set for TypeScript 4.x
}