Tslint: No unused variable for type alias and interface when used as generics.

Created on 2 Apr 2017  ·  24Comments  ·  Source: palantir/tslint

Bug Report

  • __TSLint version__: 5.0.0
  • __TypeScript version__: 2.2.2
  • __Running TSLint via__: CLI

TypeScript code being linted

describe('Action', () => {
    describe('actionCreator', () => {
        type DummyActionType = 'FOO' | 'BAR';

        interface Point {
            readonly x: number;
            readonly y: number;
        }

        it('creates the correct FSA for primitives', () => {
            const creator = actionCreator<DummyActionType, number>('FOO');
            creator(7).should.deep.equal({ type: 'FOO', payload: 7 });
        });

        it('creates the correct FSA for objects', () => {
            const creator = actionCreator<DummyActionType, Point>('BAR');
            creator({ x: 1, y: 3 }).should.deep.equal({
                type: 'BAR',
                payload: { x: 1, y: 3 },
            });
        });
    });
});

with tslint.json configuration:

{
    "defaultSeverity": "error",
    "extends": [
        // "tslint-microsoft-contrib",
        "tslint:recommended",
        "tslint-react"
    ],

    "rulesDirectory": [
        "./node_modules/tslint-immutable/rules"
    ],

    // additional rules aside from inherited ones
    "rules": {
        "arrow-parens": [true, "ban-single-arg-parens"],

        // possible errors (core TSLint)
        "no-switch-case-fall-through": true,
        "no-string-throw": true,

        // stylistic (core TSLint)
        "array-type": [true, "array"],
        "interface-name": [true, "never-prefix"],
        "no-null-keyword": true,
        "no-require-imports": true,
        "object-literal-sort-keys": false,
        "ordered-imports": [false], // array makes VSCode happy
        "quotemark": [true, "single", "jsx-double", "avoid-escape"],

        // best practices (core TSLint)
        "linebreak-style": [true, "LF"],
        "max-file-line-count": [true, 300],
        "max-line-length": [true, 100],
        "no-magic-numbers": true,
        "no-unused-expression": true,
        "no-unused-variable": [true, "check-parameters", "react"],
        "one-line": [false],
        "prefer-const": true,

        // functional programming
        "no-let": true, // no-var on by default
        "no-this": true,
        "no-class": true,
        "no-new": false, // records?
        "readonly-interface": true,
        "readonly-indexer": true,
        "readonly-array": true,
        "no-mixed-interface": true,

        // react
        "jsx-no-multiline-js": false,

        // legal
        "file-header": [true, "[+ ]{10,}"]
    }
}

Actual behavior

It marks the type alias and interface as unused.

src/frontend/actions/Action.test.ts
'DummyActionType' is declared but never used. (no-unused-variable)
  15 | describe('Action', () => {
  16 |     describe('actionCreator', () => {
> 17 |         type DummyActionType = 'FOO' | 'BAR';
     |             ^
  18 | 
  19 |         interface Point {
  20 |             readonly x: number;

'Point' is declared but never used. (no-unused-variable)
  17 |         type DummyActionType = 'FOO' | 'BAR';
  18 | 
> 19 |         interface Point {
     |                  ^
  20 |             readonly x: number;
  21 |             readonly y: number;
  22 |         }

Expected behavior

The type alias and interface are used as generic arguments, and should have no lint errors.

P1 Requires Type Checker Fixed Bug

Most helpful comment

We're still experiencing this too. Here's a minimal repo (smallest I can find):

box.ts:

export class Box<T> {
  value: T;
}

box_holder.ts:

import { Box } from './box';

export class BoxHolder<T> {
  box: Box<T>;
}

Result:

ERROR: src/base/tests/box_holder.ts[3, 24]: 'T' is declared but never used.

Versions:

  • tslint: 5.1.0
  • typescript: 2.3.0

All 24 comments

Looks like Microsoft/TypeScript#14953

My code does typecheck, so it doesn't seem to be a Typescript error. As a "workaround", I have "noUnusedLocals" and "noUnusedParameters" turned on in tsconfig, and no-unused-variable turned off.

In this file

import {buildModel} from '../src/compile/common';
import {FacetModel} from '../src/compile/facet';
import {LayerModel} from '../src/compile/layer';
import {Model} from '../src/compile/model';
import {UnitModel} from '../src/compile/unit';
import {initConfig} from '../src/config';
import {ExtendedSpec, FacetSpec, LayerSpec, normalize, TopLevel, UnitSpec} from '../src/spec';

export function parseModel(inputSpec: TopLevel<ExtendedSpec>): Model {
  const spec = normalize(inputSpec);
  return buildModel(spec, null, '', initConfig(inputSpec.config));
}

export function parseUnitModel(spec: TopLevel<UnitSpec>) {
  return new UnitModel(spec, null, '', initConfig(spec.config));
}

export function parseLayerModel(spec: TopLevel<LayerSpec>) {
  return new LayerModel(spec, null, '', initConfig(spec.config));
}

export function parseFacetModel(spec: TopLevel<FacetSpec>) {
  return new FacetModel(spec, null, '', initConfig(spec.config));
}

I get these errors:

ERROR: test/util.ts[7, 9]: 'ExtendedSpec' is declared but never used.
ERROR: test/util.ts[7, 23]: 'FacetSpec' is declared but never used.
ERROR: test/util.ts[7, 34]: 'LayerSpec' is declared but never used.
ERROR: test/util.ts[7, 66]: 'UnitSpec' is declared but never used.

It looks like tslint thinks that variables in generics are not used.

This is quite annoying because I cannot remove the imports. For now I have to disable the option to check for unused variables.

I don't think this is https://github.com/Microsoft/TypeScript/issues/14953. @joscha produced a clean repro in https://github.com/palantir/tslint/issues/2621 where the imports are not broken (https://gist.github.com/joscha/6633bae73fb4b143cfb685b2754259c9). Bumping priority on this.

In that case there is still the import of React (not shown). If you use declare namespace React { class Component<T, U> {} } instead, the error goes away.

I'm still experiencing this issue and no-unused-variable is still unusable in tslint 5. I'm happy to help by providing examples.

We're still experiencing this too. Here's a minimal repo (smallest I can find):

box.ts:

export class Box<T> {
  value: T;
}

box_holder.ts:

import { Box } from './box';

export class BoxHolder<T> {
  box: Box<T>;
}

Result:

ERROR: src/base/tests/box_holder.ts[3, 24]: 'T' is declared but never used.

Versions:

  • tslint: 5.1.0
  • typescript: 2.3.0

Interestingly, it seems that the name of the importing module matters. Taking the example above with box_holder.ts importing from box.ts, renaming box_holder.ts to a few different names, yields:

bo.ts: error
bo_.ts: error
bow.ts: error
box_.ts: error
box_holder.ts: error
boxa.ts: no error
boy.ts: no error
bx.ts: no error

Came here for this. I'm getting a whole bunch of new lint errors along the lines of:

ERROR: src/app/app-state.ts[1, 1]: All imports are unused.
ERROR: src/app/app.component.ts[2, 15]: 'Platform' is declared but never used.
ERROR: src/auth/auth.service.ts[2, 10]: 'Http' is declared but never used.

All of those are _not_ being used as variables, but rather _type_ definitions.

import { AuthState } from '../auth/models/auth-state'; // <-- "All imports are unused"

export declare interface AppState {
  auth: AuthState;
}

This should be fixed in typescript@next now. Could y'all test it out?

Still experiencing the same problem on [email protected]
Using [email protected]

import * as TypeMoq from 'typemoq';
import { MockedMethod } from '../mocking';
import { IComponent } from '../component';  // <-- All imports are unused
import { IComponentFactory } from '../componentfactory';

export class CreateComponentXMethodMock extends MockedMethod<IComponentFactory, IComponent> {
    constructor(mock: TypeMoq.IMock<IComponentFactory>) {
        super(mock, x => x.createComponentX(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber()));
    }
}

fixed in TS 2.4

I'm seeing this without an error in tsc:

interface SurveyAssetLayersProxyProps {
  survey: Survey
}

export default class SurveyAssetLayersControl extends React.Component<SurveyAssetLayersProxyProps, void> {
}

Gives me: ERROR: 19:11 no-unused-variable 'SurveyAssetLayersProxyProps' is declared but never used.

@mikew Maybe your tslint is running with a different TypeScript version than your tsc?

I wasn't aware that was possible. Both are relative to the project, in ./node_modules/.bin/. How would I go about confirming this?

On Jun 2, 2017, at 2:52 PM, Andy notifications@github.com wrote:

@mikew https://github.com/mikew Maybe your tslint is running with a different TypeScript version than your tsc?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/palantir/tslint/issues/2470#issuecomment-305864709, or mute the thread https://github.com/notifications/unsubscribe-auth/AAASeRvhBbEUpy0tQwk_wtObSYT9bsndks5sAEvCgaJpZM4Mws3T.

Using a different tsc in tslint is not really possible... @mikew which exact version of 2.4 nightly are you using?

@adidahiya for now, it does not work because you guys only upgrade the deps in devDependencies but not in peerDependencies. see here https://github.com/palantir/tslint/blob/3323ed2b0824a12c8b35c421ebf23c7d17cf788f/package.json#L51. Hope to get patch release ASAP :smile:

Ooh, i tried to remove and reinstall tslint. And its nested typescript gone. Some thing wrong with yarn.

i'm experiencing this issue with v5.6.0

@tolgaek Could you provide sample code? What is your TS version? Can you reproduce your error using the --noUnusedLocals compiler option instead of tslint?

hi @andy-ms I was trying to recreate this issue with simple code but the error wouldn't show up then. It looks like this error might be due to the complexity of our app somehow.

Also I couldn't run with noUnusedLocals but i get " error: unknown option `--noUnusedLocals'" error.

Here's the code I see the error on:

import { StepUpProvider } from './step-up.provider';
import { Injectable } from '@angular/core';
import {
  Http,
  XHRBackend,
  RequestOptions,
  RequestOptionsArgs,
  Response,
  Request
} from '@angular/http';
import { Observable } from 'rxjs';

@Injectable()
export class RequestInterceptor extends Http {

  constructor(
    public backend: XHRBackend,
    public defaultOptions: RequestOptions,
    private stepUpProvider: StepUpProvider
  ) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return this.stepUpProvider.intercept(super.request.bind(this, url, options));
  }
}

In the above file, I get **.ts[8, 3]: 'Response' is declared but never used. Even though Response is used to type the return value of the request function

I'm seeing this with tslint 5.10.0 and typescript 2.9.2. Any ideas?

🤖 Beep boop! 👉 TSLint is deprecated 👈 and you should switch to typescript-eslint! 🤖

🔒 This issue is being locked to prevent further unnecessary discussions. Thank you! 👋

Was this page helpful?
0 / 5 - 0 ratings

Related issues

allbto picture allbto  ·  3Comments

cateyes99 picture cateyes99  ·  3Comments

rajinder-yadav picture rajinder-yadav  ·  3Comments

Ne-Ne picture Ne-Ne  ·  3Comments

denkomanceski picture denkomanceski  ·  3Comments