Tslint: μ œλ„€λ¦­μœΌλ‘œ μ‚¬μš©λ  λ•Œ μœ ν˜• 별칭 및 μΈν„°νŽ˜μ΄μŠ€μ— λŒ€ν•΄ μ‚¬μš©λ˜μ§€ μ•ŠλŠ” λ³€μˆ˜κ°€ μ—†μŠ΅λ‹ˆλ‹€.

에 λ§Œλ“  2017λ…„ 04μ›” 02일  Β·  24μ½”λ©˜νŠΈ  Β·  좜처: palantir/tslint

버그 μ‹ κ³ 

  • __TSLint 버전__: 5.0.0
  • __νƒ€μž…μŠ€ν¬λ¦½νŠΈ 버전__: 2.2.2
  • ____λ₯Ό 톡해 TSLint μ‹€ν–‰ν•˜κΈ°: CLI

λ¦°νŠΈλ˜λŠ” TypeScript μ½”λ“œ

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 },
            });
        });
    });
});

tslint.json ꡬ성:

{
    "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,}"]
    }
}

μ‹€μ œ 행동

μœ ν˜• 별칭과 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ€ κ²ƒμœΌλ‘œ ν‘œμ‹œν•©λ‹ˆλ‹€.

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 |         }

μ˜ˆμƒλ˜λŠ” 행동

μœ ν˜• 별칭 및 μΈν„°νŽ˜μ΄μŠ€λŠ” 일반 인수둜 μ‚¬μš©λ˜λ©° 린트 였λ₯˜κ°€ μ—†μ–΄μ•Ό ν•©λ‹ˆλ‹€.

P1 Requires Type Checker Fixed Bug

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μš°λ¦¬λ„ μ—¬μ „νžˆ 이것을 κ²ͺκ³  μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ μ΅œμ†Œν•œμ˜ λ¦¬ν¬μ§€ν† λ¦¬μž…λ‹ˆλ‹€(λ‚΄κ°€ 찾을 수 μžˆλŠ” κ°€μž₯ μž‘μ€ 것).

box.ts:

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

box_holder.ts:

import { Box } from './box';

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

κ²°κ³Ό:

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

버전:

  • ν‹°μŠ¬λ¦°νŠΈ: 5.1.0
  • νƒ€μ΄ν”„μŠ€ν¬λ¦½νŠΈ: 2.3.0

λͺ¨λ“  24 λŒ“κΈ€

Microsoft/TypeScript#14953처럼 λ³΄μž…λ‹ˆλ‹€.

λ‚΄ μ½”λ“œλŠ” μœ ν˜• 검사λ₯Ό μˆ˜ν–‰ν•˜λ―€λ‘œ Typescript 였λ₯˜κ°€ μ•„λ‹Œ 것 κ°™μŠ΅λ‹ˆλ‹€. "ν•΄κ²° 방법"으둜 tsconfigμ—μ„œ "noUnusedLocals" 및 "noUnusedParameters" 켜고 no-unused-variable λ₯Ό λ•λ‹ˆλ‹€.

이 νŒŒμΌμ—μ„œ

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));
}

λ‹€μŒκ³Ό 같은 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

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.

tslintλŠ” μ œλ„€λ¦­μ˜ λ³€μˆ˜κ°€ μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€κ³  μƒκ°ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

μˆ˜μž…ν’ˆμ„ μ œκ±°ν•  수 μ—†κΈ° λ•Œλ¬Έμ— 이것은 μƒλ‹Ήνžˆ μ„±κ°€μ‹  μΌμž…λ‹ˆλ‹€. μ§€κΈˆμ€ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” λ³€μˆ˜λ₯Ό ν™•μΈν•˜λŠ” μ˜΅μ…˜μ„ λΉ„ν™œμ„±ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ‚˜λŠ” 이것이 https://github.com/Microsoft/TypeScript/issues/14953 이라고 μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ @joscha λŠ” κ°€μ Έμ˜€κΈ°κ°€ μ€‘λ‹¨λ˜μ§€ μ•Šμ€ https://github.com/palantir/tslint/issues/2621 μ—μ„œ κΉ¨λ—ν•œ μž¬ν˜„μ„ μƒμ„±ν–ˆμŠ΅λ‹ˆλ‹€(https://gist.github.com/joscha/6633bae73fb4b143cfb685b2754259c9). 이것에 μš°μ„  μˆœμœ„λ₯Ό λ‘μ‹­μ‹œμ˜€.

이 경우 μ—¬μ „νžˆ React κ°€μ Έμ˜€κΈ°κ°€ μžˆμŠ΅λ‹ˆλ‹€(ν‘œμ‹œλ˜μ§€ μ•ŠμŒ). λŒ€μ‹  declare namespace React { class Component<T, U> {} } μ‚¬μš©ν•˜λ©΄ 였λ₯˜κ°€ μ‚¬λΌμ§‘λ‹ˆλ‹€.

μ—¬μ „νžˆ 이 λ¬Έμ œκ°€ λ°œμƒν•˜κ³  no-unused-variable λŠ” μ—¬μ „νžˆ tslint 5μ—μ„œ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. 기꺼이 예제λ₯Ό μ œκ³΅ν•˜μ—¬ λ„μ™€λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

μš°λ¦¬λ„ μ—¬μ „νžˆ 이것을 κ²ͺκ³  μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ μ΅œμ†Œν•œμ˜ λ¦¬ν¬μ§€ν† λ¦¬μž…λ‹ˆλ‹€(λ‚΄κ°€ 찾을 수 μžˆλŠ” κ°€μž₯ μž‘μ€ 것).

box.ts:

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

box_holder.ts:

import { Box } from './box';

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

κ²°κ³Ό:

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

버전:

  • ν‹°μŠ¬λ¦°νŠΈ: 5.1.0
  • νƒ€μ΄ν”„μŠ€ν¬λ¦½νŠΈ: 2.3.0

ν₯λ―Έλ‘­κ²Œλ„ κ°€μ Έμ˜€λŠ” λͺ¨λ“ˆμ˜ 이름이 μ€‘μš”ν•œ 것 κ°™μŠ΅λ‹ˆλ‹€. box_holder.ts μ—μ„œ box.ts box_holder.ts κ°€μ Έμ˜€κΈ°λ₯Ό μ‚¬μš©ν•˜μ—¬ μœ„μ˜ 예λ₯Ό μ‚¬μš©ν•˜λ©΄ box_holder.ts 이름을 λͺ‡ 가지 λ‹€λ₯Έ μ΄λ¦„μœΌλ‘œ λ°”κΎΈλ©΄ λ‹€μŒμ΄ μƒμ„±λ©λ‹ˆλ‹€.

bo.ts : 였λ₯˜
bo_.ts : 였λ₯˜
bow.ts : 였λ₯˜
box_.ts : 였λ₯˜
box_holder.ts : 였λ₯˜
boxa.ts : 였λ₯˜ μ—†μŒ
boy.ts : 였λ₯˜ μ—†μŒ
bx.ts : 였λ₯˜ μ—†μŒ

이것을 μœ„ν•΄ 여기에 μ™”μŠ΅λ‹ˆλ‹€. λ‹€μŒ 라인을 따라 μƒˆλ‘œμš΄ 보푸라기 였λ₯˜κ°€ 많이 λ°œμƒν•©λ‹ˆλ‹€.

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.

이듀 λͺ¨λ‘λŠ” λ³€μˆ˜λ‘œ μ‚¬μš©λ˜λŠ” _not_이 μ•„λ‹ˆλΌ _type_ μ •μ˜μž…λ‹ˆλ‹€.

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

export declare interface AppState {
  auth: AuthState;
}

이것은 μ§€κΈˆ typescript@next μ—μ„œ μˆ˜μ •λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. ν…ŒμŠ€νŠΈν•΄ λ³΄μ‹œκ² μ–΄μš”?

[email protected] μ—μ„œ μ—¬μ „νžˆ λ™μΌν•œ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.
[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()));
    }
}

μ•Œκ² μŠ΅λ‹ˆλ‹€. 문제λ₯Ό λ‹€μ‹œ μ—΄μ—ˆμŠ΅λ‹ˆλ‹€. https://github.com/Microsoft/TypeScript/issues/14953#issuecomment -302101264

TS 2.4μ—μ„œ μˆ˜μ •λ¨

tsc μ—μ„œ 였λ₯˜ 없이 이것을 보고 μžˆμŠ΅λ‹ˆλ‹€.

interface SurveyAssetLayersProxyProps {
  survey: Survey
}

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

λ‚˜μ—κ²Œ μ€€λ‹€: ERROR: 19:11 no-unused-variable 'SurveyAssetLayersProxyProps' is declared but never used.

@mikew μ•„λ§ˆλ„ tslint 이 tsc 와 λ‹€λ₯Έ TypeScript λ²„μ „μœΌλ‘œ μ‹€ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?

그게 κ°€λŠ₯ν•œμ§€ λͺ°λžμŠ΅λ‹ˆλ‹€. λ‘˜ λ‹€ ./node_modules/.bin/ μ—μ„œ ν”„λ‘œμ νŠΈμ— μƒλŒ€μ μž…λ‹ˆλ‹€. 이λ₯Ό ν™•μΈν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν•©λ‹ˆκΉŒ?

2017λ…„ 6μ›” 2일 μ˜€ν›„ 2μ‹œ 52뢄에 Andy [email protected]이 λ‹€μŒκ³Ό 같이 μΌμŠ΅λ‹ˆλ‹€.

@mikew https://github.com/mikew μ•„λ§ˆλ„ tslintκ°€ tsc와 λ‹€λ₯Έ TypeScript λ²„μ „μœΌλ‘œ μ‹€ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆκΉŒ?

β€”
당신이 μ–ΈκΈ‰λ˜μ—ˆκΈ° λ•Œλ¬Έμ— 이것을 λ°›λŠ” κ²ƒμž…λ‹ˆλ‹€.
이 이메일에 직접 νšŒμ‹ ν•˜κ±°λ‚˜ GitHub https://github.com/palantir/tslint/issues/2470#issuecomment-305864709 μ—μ„œ ν™•μΈν•˜κ±°λ‚˜ μŠ€λ ˆλ“œ https://github.com/notifications/unsubscribe-auth/AAASeRvhBbEUpy0tQwk_wtObSYT9bsCwksλ₯Ό μŒμ†Œκ±°

λ‹€λ₯Έ μ‚¬μš© tsc μ—μ„œ tslint 2.4의 μ •ν™•ν•œ 버전은 밀에 μ‚¬μš©ν•˜λŠ” 정말 μ•„λ‹ˆλ‹€ κ°€λŠ₯ ... @mikewλ₯Ό?

@adidahiya ν˜„μž¬ devDependencies μ—μ„œλ§Œ depsλ₯Ό μ—…κ·Έλ ˆμ΄λ“œν•˜κ³  peerDependencies μ—μ„œλŠ” μ—…κ·Έλ ˆμ΄λ“œν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ—¬κΈ°λ₯Ό μ°Έμ‘°ν•˜μ‹­μ‹œμ˜€ https://github.com/palantir/tslint/blob/3323ed2b0824a12c8b35c421ebf23c7d17cf788f/package.json#L51. 패치 릴리슀λ₯Ό μ΅œλŒ€ν•œ 빨리 λ°›κΈ°λ₯Ό λ°”λžλ‹ˆλ‹€ :슀마일:

였, tslintλ₯Ό μ œκ±°ν•˜κ³  λ‹€μ‹œ μ„€μΉ˜ν•˜λ €κ³  ν–ˆμŠ΅λ‹ˆλ‹€. 그리고 μ€‘μ²©λœ νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ μ‚¬λΌμ‘ŒμŠ΅λ‹ˆλ‹€. 싀에 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

v5.6.0μ—μ„œ 이 λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.

@tolgaek μƒ˜ν”Œ μ½”λ“œλ₯Ό μ œκ³΅ν•΄ μ£Όμ‹œκ² μŠ΅λ‹ˆκΉŒ? λ‹Ήμ‹ μ˜ TS 버전은 λ¬΄μ—‡μž…λ‹ˆκΉŒ? tslint λŒ€μ‹  --noUnusedLocals 컴파일러 μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ 였λ₯˜λ₯Ό μž¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

μ•ˆλ…•ν•˜μ„Έμš” @andy-ms κ°„λ‹¨ν•œ μ½”λ“œλ‘œ 이 문제λ₯Ό μž¬ν˜„ν•˜λ €κ³  ν–ˆμ§€λ§Œ 였λ₯˜κ°€ ν‘œμ‹œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이 였λ₯˜λŠ” μ–΄λ–»κ²Œ λ“  μ•±μ˜ λ³΅μž‘μ„±μœΌλ‘œ μΈν•œ 것 κ°™μŠ΅λ‹ˆλ‹€.

λ˜ν•œ noUnusedLocals μ‹€ν–‰ν•  수 μ—†μ§€λ§Œ " error: unknown option `--noUnusedLocals'" 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

λ‹€μŒμ€ 였λ₯˜κ°€ ν‘œμ‹œλ˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

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));
  }
}

μœ„μ˜ νŒŒμΌμ—μ„œ λ‚΄κ°€ 얻을 **.ts[8, 3]: 'Response' is declared but never used. μžˆμ§€λ§Œ Response 의 λ°˜ν™˜ 값을 μž…λ ₯ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€ request κΈ°λŠ₯을

tslint 5.10.0 및 typescript 2.9.2μ—μ„œ 이것을 보고 μžˆμŠ΅λ‹ˆλ‹€. μ–΄λ–€ 아이디어?

πŸ€– 삐삐! πŸ‘‰ TSLintλŠ” 더 이상 μ‚¬μš©λ˜μ§€ μ•ŠμœΌλ©° πŸ‘ˆ typescript-eslint둜 μ „ν™˜ ν•΄μ•Ό

πŸ”’ 이 μ΄μŠˆλŠ” 더 μ΄μƒμ˜ λΆˆν•„μš”ν•œ 토둠을 λ°©μ§€ν•˜κΈ° μœ„ν•΄ 잠그고 μžˆμŠ΅λ‹ˆλ‹€. κ°μ‚¬ν•©λ‹ˆλ‹€! πŸ‘‹

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰