npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

eslint-plugin-total-functions

v7.1.0

Published

An ESLint plugin to enforce the use of TypeScript total functions.

Downloads

10,508

Readme

TypeScript Total Functions - ESLint Plugin

Build Status Type Coverage Test Coverage Mutation testing badge Known Vulnerabilities Codacy Badge npm

An ESLint plugin to enforce the use of total functions (and prevent the use of partial functions) in TypeScript. If you like your types to tell the truth, this is the ESLint plugin for you.

Version Matrix

| TypeScript | ESLint | eslint-plugin-total-functions | Suppported? | | :--------------: | :-----: | :---------------------------: | :---------: | | 5.0.2 | 8.36.0 | 7.0.0 | | | 4.9.5 | 8.35.0 | 6.2.0 | No | | 4.7.3 | 8.17.0 | 6.0.0 | No | | 4.5.4 | 8.5.0 | 5.0.0 | No | | 4.4.2 | 7.32.0 | 4.10.1 | No | | 4.3.5 | 7.30.0 | 4.8.0 | No | | 4.1.2 | 7.12.0 | 4.7.2 | No | | 4.0.2 | 7.9.0 | 3.3.0 | No |

Installation

yarn add --dev eslint-plugin-total-functions \
  @typescript-eslint/parser \
  eslint \
  typescript

Setup

Option 1

Use eslint-config-typed-fp which includes this plugin among others.

Option 2

  1. Turn on TypeScript's strict mode and noUncheckedIndexedAccess option.
  2. Set up ESLint + TypeScript.
  3. Turn on eslint-plugin-functional (recommended). Its rules related to mutation and OO are more important than this plugin's rules and they'll help keep your types honest.
  4. Update your .eslintrc.js:
module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: "./tsconfig.json",
    ecmaVersion: 2018,
    sourceType: "module"
  },
  extends: [
+    "plugin:total-functions/recommended",
  ],
  plugins: [
+    "total-functions",
  ],
};

Alternatively you can configure individual rules separately (see below).

Rules

| Rule | Recommended | All | Fixer? | | :-------------------------------------: | :----------: | :---: | :----: | | require-strict-mode | ✅ | ✅ | | | no-unsafe-type-assertion | ✅ | ✅ | | | no-unsafe-readonly-mutable-assignment | ✅ | ✅ | | | no-unsafe-mutable-readonly-assignment | | ✅ | | | no-enums | ✅ | ✅ | | | no-partial-url-constructor | ✅ | ✅ | | | no-partial-division | ✅ | ✅ | | | no-partial-string-normalize | ✅ | ✅ | | | no-premature-fp-ts-effects | ✅ | ✅ | | | no-nested-fp-ts-effects | | ✅ | | | no-partial-array-reduce | ✅ | ✅ | | | no-hidden-type-assertions | | ✅ | |

Deprecated rules

  • no-unsafe-optional-property-assignment
  • no-unsafe-enum-assignment (No longer required as of TypeScript 5, see https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#all-enums-are-union-enums)

total-functions/require-strict-mode

The world is a very strange place when strict mode is disabled. This rule enforces strict mode and noUncheckedIndexedAccess mode (which is sadly not included under the strict umbrella).

total-functions/no-unsafe-type-assertion

Bans unsafe type assertions, for example:

type Foo = { readonly bar: number };
const foo = {} as Foo; // This compiles
foo.bar.toString(); // This explodes at runtime

This is similar to the consistent-type-assertions rule from typescript-eslint, however:

  1. this rule is weaker than consistent-type-assertions with its assertionStyle option set to never -- this rule will permit type assertions that it considers safe as opposed to blanket banning all type assertions, and
  2. this rule is stronger than consistent-type-assertions with its objectLiteralTypeAssertions option set to never, for example:
type Foo = { readonly bar: number };
const foo = {};
const foo2 = foo as Foo; // Flagged by this rule, but not by consistent-type-assertions (unless you set assertionStyle to never)
foo2.bar.toString(); // This explodes at runtime

For examples of type assertions that this rule considers valid and invalid, see no-unsafe-type-assertion.test.ts.

See TypeScript issue #7481 for a request to fix this at the language level.

total-functions/no-unsafe-readonly-mutable-assignment

Bans unsafe assignment of readonly values to mutable values (which can lead to surprising mutation in the readonly value). This includes passing readonly values as arguments to functions that expect mutable parameters.

For examples of assignment that this rule considers valid and invalid, see no-unsafe-readonly-mutable-assignment.test.ts.

See TypeScript issue #13347 for a request to fix this at the language level.

total-functions/no-unsafe-mutable-readonly-assignment

The inverse counterpart to no-unsafe-readonly-mutable-assignment. This rule bans unsafe assignment of mutable values to readonly values (which just like the inverse can lead to surprising mutation in the readonly value).

This rule is often noisy in practice so, unlike no-unsafe-readonly-mutable-assignment, is excluded from the recommended config.

Note that the following is considered an assignment from mutable to readonly:

  type ReadonlyA = { readonly a: string };
  const readonlyA: ReadonlyA = { a: "" };

The solution is to append as const to the RHS:

  type ReadonlyA = { readonly a: string };
  const readonlyA: ReadonlyA = { a: "" } as const;

For examples of assignment that this rule considers valid and invalid, see no-unsafe-mutable-readonly-assignment.test.ts.

total-functions/no-enums

Enums have a number of issues, including unsoundness issues (which are especially relevant here). This rule bans the declaration of enums entirely. Use an alternative such as a union of strings instead.

total-functions/no-unsafe-enum-assignment

Deprecated No longer required as of TypeScript 5 (https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#all-enums-are-union-enums).

If you do use an enum (or are forced to by a library), this rule flags unsafe assignment that the TypeScript compiler (prior to version 5) permits. For example:

  enum ZeroOrOne {
    Zero = 0,
    One = 1,
  }

  // This compiles (prior to TypeScript 5) but is flagged by no-unsafe-enum-assignment
  const zeroOrOne: ZeroOrOne = 2;

  // This is not flagged by no-unsafe-enum-assignment
  const zeroOrOne: ZeroOrOne = ZeroOrOne.Zero;

total-functions/no-partial-url-constructor

The URL constructor can throw (i.e. it is partial).

// This compiles and foo appears to be a URL. It isn't.
const foo: URL = new URL(""); // Throws TypeError [ERR_INVALID_URL]: Invalid URL

Instead, you should use a wrapper that catches that error and returns URL | undefined or similar (perhaps using an Option type).

URL also happens to be mutable, which will be flagged by prefer-immutable-types. The readonly-types package provides a readonlyURL function that solves both of these issues.

total-functions/no-partial-division

Division by zero is undefined. That makes the division operator partial.

In the case of number, it results in Infinity (IEEE 754...).

In the case of bigint it throws a RangeError.

The latter is much more indisputably partial than the former.

> 1 / 0
Infinity
> 1n / 0n
Uncaught RangeError: Division by zero

This rule flags division unless the denominator is provably non-zero. If you need division, you should wrap it in a wrapper that returns undefined when the denominator is zero. Alternatively, consider using branded types / refinements, such as https://github.com/gcanti/io-ts/blob/master/index.md#branded-types--refinements or https://gcanti.github.io/newtype-ts/modules/NonZero.ts.html

See Also

  • TypeScript for Functional Programmers
  • https://github.com/danielnixon/eslint-config-typed-fp
  • https://github.com/agiledigital/readonly-types
  • https://github.com/eslint-functional/eslint-plugin-functional
  • https://github.com/RebeccaStevens/is-immutable-type
  • https://github.com/gcanti/fp-ts
  • https://github.com/plantain-00/type-coverage
  • https://github.com/immutable-js/immutable-js
  • https://github.com/shian15810/eslint-plugin-typescript-enum