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 | }
μ ν λ³μΉ λ° μΈν°νμ΄μ€λ μΌλ° μΈμλ‘ μ¬μ©λλ©° λ¦°νΈ μ€λ₯κ° μμ΄μΌ ν©λλ€.
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.
λ²μ :
ν₯λ―Έλ‘κ²λ κ°μ Έμ€λ λͺ¨λμ μ΄λ¦μ΄ μ€μν κ² κ°μ΅λλ€. 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λ‘ μ ν ν΄μΌ
π μ΄ μ΄μλ λ μ΄μμ λΆνμν ν λ‘ μ λ°©μ§νκΈ° μν΄ μ κ·Έκ³ μμ΅λλ€. κ°μ¬ν©λλ€! π
κ°μ₯ μ μ©ν λκΈ
μ°λ¦¬λ μ¬μ ν μ΄κ²μ κ²ͺκ³ μμ΅λλ€. λ€μμ μ΅μνμ 리ν¬μ§ν 리μ λλ€(λ΄κ° μ°Ύμ μ μλ κ°μ₯ μμ κ²).
box.ts:
box_holder.ts:
κ²°κ³Ό:
λ²μ :