Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[prefer-readonly-parameter-types] inferred types from third party code make rule painful #2079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
osdiab opened this issue May 23, 2020 · 6 comments
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule good first issue Good for newcomers locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@osdiab
Copy link

osdiab commented May 23, 2020

i like the concept of the checker, but it's a pain in the butt in practice if you use third party libraries with typings and hope to use typescript's inference engine, because it errors like crazy.

Repro
Install one of many popular libraries:

yarn add -D ava
# or maybe
yarn add io-ts
{
  "rules": {
    "@typescript-eslint/prefer-readonly-parameter-types": ["error"]
  }
}
// ava - t is not deeply readonly so it errors
// ava's typings don't make this deeply readonly, so it's clear why this would fail
import test from "ava";
test('Stub', (t) => {
	t.is(1, 1);
});

or maybe

import t from io-ts;

// this fails as well - which is extra frustrating since that library even goes to lengths to make things readonly in its typings!
// though I'm guessing it's triggering on the `unknown` values, which isnt feasible to eliminate for this library
// https://github.com/gcanti/io-ts/blob/73d92a08c42dca3d874927d92c8e9ad30d0a11f5/src/index.ts#L28
const parseValidationError = (error: t.ValidationError) => {
  return error;
}

Expected Result

  • that there be configuration options to make the rule more usable for third party typings, some kind of escape hatch that doesn't involve adding an eslint ignore comment over and over again all over my app for inferred types - for example the unknown values in io-ts are essential to its usage, and I trust it, so I'm OK with letting anything from io-ts slide
  • also that there be a little more detail on what exactly was not readonly, since it's sometimes not straightforward to tell from complex types especially from third party libraries what might be wrong, so it's hard for me to make ticket for third parties when it happens

Actual Result
Errors that I can't fix since it's not my typings, besides just ignoring the rule or turning it off

Versions

package version
@typescript-eslint/eslint-plugin 2.29.0
@typescript-eslint/parser 2.29.0
TypeScript 3.9.3
ESLint 6.8.0
node 12.16.3
npm 6.14.4
@osdiab osdiab added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels May 23, 2020
@bradzacher
Copy link
Member

I believe that the reason that t.ValidationError isn't considered readonly is due to its Context type, which is interface Context extends ReadonlyArray<ContextEntry> {}.
Due to limitations in the compiler API, it's not easy to detect an interface that extends the base array types.

If they had instead used type Context = ReadonlyArray<ContextEntry>, then it would work fine.


I don't think it's unreasonable to add an option to ignore functions in a callback position.

@bradzacher bradzacher added enhancement: plugin rule option New rule option for an existing eslint-plugin rule and removed triage Waiting for team members to take a look labels May 23, 2020
@devkabiir
Copy link

devkabiir commented Oct 8, 2020

I'm not sure how much api is available for this but something like the following would solve most common use cases I think.

global.d.ts
// Just an alias to the original type
/**
 * Explicitly mark a type T as allowed for `prefer-readonly-parameter-types`
 * ⚠ `Only use it when you know what you're doing` <- Or some similar warning text
 */
declare type Mutable<T = unknown> = T;
eslintrc.yaml
      '@typescript-eslint/prefer-readonly-parameter-types':
        - error
        # Either
        - allowedTypes: ['Mutable<*>'] # Regex/Glob pattern to exclude
        # Or
        - allowedTypes: ['./global.d.ts#Mutable'] # Full path to the type itself relative to the config file
        # Or
        - allowedTypes: ['io-ts', 'package-name', 'package-name/specific/type/import/path'] # Package name or path to package specific type as it would be if it was imported
        # Or
        - allowThirdParty: true # Any type that is not declared within the tsconfig project src/root being linted
test.ts
import t from io-ts;

// No errors here
const parseValidationError = (error: Mutable<t.ValidationError>) => {
  return error;
}

// Or here
const parseValidationError = (error: t.ValidationError) => {
  return error;
}

The above Mutable approach is not really any different than an eslint-ignore comment all over the place and it might not even work given that the actual resolved type is the same as the original however it might be useful as a regex/pattern based allow list. The package-name approach would allow for a granular control while allowThirdParty would be en escape hatch and probably most widely used if implemented.

I don't think it's unreasonable to add an option to ignore functions in a callback position.

+1 For that as well

@eyelidlessness
Copy link
Contributor

I'm setting up a project and... this is indeed painful. So much so that I'm likely to disable it and accept mutation risks that I'd like to avoid. The discussion here is interesting, but...

I don't think it's unreasonable to add an option to ignore functions in a callback position.

I'm not sure this is the best solution. What I would want is:

  • If a parameter's type is inferred, the definition that supplies that inference should be the place the linter checks (and if it's out of scope, it should not result in an error).
  • If an inferred parameter is mutable, the linter should treat it as readonly anyway, for purposes of in-scope mutation, assignment to a mutable type, or passing as a mutable parameter to another function.

Given the prevalence of mutable types even in libraries that strongly focus on pure functional patterns (the io-ts library which produced this error for the OP being one of them), I don't really see how this rule can be usable without those changes (or something like them).

@bradzacher bradzacher added the good first issue Good for newcomers label Oct 11, 2020
@bradzacher
Copy link
Member

There's always the option to contribute fixes upstream?
If the types are mutable when they really shouldn't be - a PR to the source of the types can fix that for everyone, even those that don't use this rule.


Happy to accept a PR to add a new option to ignore parameters without an explicit type annotation.

As with almost everything in this project - this rule is maintained by the community. The best and fastest way to see a change done is to roll up your sleeve and contribute!

This is a pointer to roughly where you'd need to start making a change:

if (
!checkParameterProperties &&
param.type === AST_NODE_TYPES.TSParameterProperty
) {
continue;
}
const actualParam =
param.type === AST_NODE_TYPES.TSParameterProperty
? param.parameter
: param;

@eyelidlessness
Copy link
Contributor

@bradzacher thanks! I'll take a look and see if I can make some progress on the change, I'd be happy to contribute.

@Josh-Cena
Copy link
Member

At this state I would call it fixed by #2668 since it seems the only agreement reached is to "ignore parameters without an explicit type annotation", which ignoreInferredTypes does. If anyone has anything else they want to see, please open a new issue.

@github-actions github-actions bot added the locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. label Jun 9, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 9, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule good first issue Good for newcomers locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
Development

No branches or pull requests

6 participants