Neurotic Programmer Masquerade
    Wondering what’s next for npm?Check out our public roadmap! »

    eslint-plugin-total-functions

    4.7.2 • Public • Published

    TypeScript Total Functions - ESLint Plugin

    Type Coverage Test Coverage Mutation testing badge Known Vulnerabilities Total alerts Language grade: JavaScript npm

    dependencies Status devDependencies Status peerDependencies Status

    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
    4.1.2 7.12.0 4.7.0
    4.0.2 7.9.0 3.3.0

    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 Not yet
    no-unsafe-optional-property-assignment Not yet
    no-unsafe-subscript Deprecated
    no-unsafe-destructuring Deprecated

    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-unsafe-optional-property-assignment

    Optional properties (those with a ? after their name) interact badly with TypeScript's structural type system in a way that can lead to unsoundness. Example:

    type Foo = { readonly foo: string };
    type Bar = Foo & { readonly bar?: () => unknown };
     
    const thing = { foo: "foo", bar: "bar" };
    const foo: Foo = thing;
    const bar: Bar = foo;
     
    if (bar.bar !== undefined) {
        bar.bar(); // explodes at runtime
    }

    I find this scenario particularly vexing because it doesn't require type assertions, or plain JS with incorrect *.d.ts typings, or anything 'loose' like that. You can pull it off with otherwise nicely typed, functional TypeScript (strict mode enabled, no interfaces, no classes, everything readonly, everything const, no type assertions, no plain JS, etc).

    This rule bans assignment from one type to another, if:

    1. the destination type has an optional property, and
    2. the source type has no matching property (either optional or otherwise).

    This rule is excluded from the recommended config until #83 lands.

    total-functions/no-unsafe-subscript

    Prior to TypeScript 4.1's noUncheckedIndexedAccess option, member access for arrays and records was not type safe. For example:

    const a: string[] = [];
    const b = a[0]; // b has type string, not string | undefined as you might expect
    b.toUpperCase(); // This explodes at runtime
     
    const record: Record<string, string> = { foo: "foo" };
    const bar = record["bar"]; // bar has type string, not string | undefined
    bar.toUpperCase(); // This explodes at runtime
     
    const baz = record.baz; // baz has type string, not string | undefined
    baz.toUpperCase(); // This explodes at runtime
     
    const str = "";
    const s = str[0]; // s has type string, not string | undefined
    s.toUpperCase(); // This explodes at runtime

    This rule bans unsafe member access. Only use this rule if you are stuck on Typescript < 4.1. This rule is deprecated and excluded from the recommended config. It may be removed in the future.

    For examples of member access that this rule considers valid and invalid, see no-unsafe-subscript.test.ts.

    total-functions/no-unsafe-destructuring

    Prior to TypeScript 4.1's noUncheckedIndexedAccess option, destructuring arrays and records was not type safe. For example:

    const array: readonly string[] = [];
    const [foo] = array; // foo has type string, not string | undefined
    foo.toUpperCase(); // This explodes at runtime
     
    const obj: Record<string, string> = { a: "a" };
    const { b } = obj; // b has type string, not string | undefined
    b.toUpperCase(); // This explodes at runtime
     
    const str = "";
    const [bar] = str; // bar has type string, not string | undefined
    bar.toUpperCase(); // This explodes at runtime

    This rule bans unsafe destructuring. Only use this rule if you are stuck on Typescript < 4.1. This rule is deprecated and excluded from the recommended config. It may be removed in the future.

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

    See Also

    Keywords

    none

    Install

    npm i eslint-plugin-total-functions

    DownloadsWeekly Downloads

    787

    Version

    4.7.2

    License

    MIT

    Unpacked Size

    363 kB

    Total Files

    106

    Last publish

    Collaborators

    • avatar