Show / Hide Table of Contents

Refactoring & Quick fixes

Availability

Refactorings

Refactorings are supported as of Visual Studio 2017 version 15.4.0.

TS Version Effects
2.4.0 Convert to ES6 class
2.5.0 Extract function
2.6.0 Extract constant
2.6.1 Annotate with type from JSDoc
2.6.1 Install @types for JS module
TBD Convert to default import

Code Fixes

Code fixes are supported as of Visual Studio 2017 version 15.0.0.

TS Version Error Codes Effects
2.1.4 2304, 2503, 2552, 2686 Add an appropriate import (?)
2.2.1 2339, 2551 Add missing member
2.2.1 2377 Synthesize missing super() call
2.2.1 2420 Implement interface members
2.2.1 2515, 2653 Implement abstract members from base class
2.2.1 2663 Prepend this. to member access
2.2.1 2689 Change extends to implements
2.2.1 17009 Move super() call ahead of this access
2.3.0 All Suppress JS diagnostic
2.4.0 2551, 2552 Correct misspelled name
2.4.1 6133, 6138 Handle unused symbol
2.5.0 2713 Rewrite as indexed access type
2.5.0 8020 Convert JSDoc type to TS type
2.6.1 1329 Call decorator factory expression
2.6.1 7005, 7006, 7008, 7010, 7019, 7032, 7033, 7034 Annotate with inferred type
2.6.1 7016 Install @types for JS module

Examples

Refactorings

Convert to ES6 Class

Before

function cls() {
    this.x = 10;
}
cls.prototype.method = function () {
    return 3;
}

After

class cls
{
    constructor()
    {
        this.x = 10;
    }
    method()
    {
        return 3;
    }
}

Notes

  • Only applies in JavaScript files.
  • The caret must be on an occurrence of the class name.

Extract Function

Before

function F(x: number)
{
    /*start*/return x + 1;/*end*/
}

After - Nested Function

function F(x: number)
{
    return newFunction();

    function newFunction()
    {
        return x + 1;
    }
}

After - Top-Level Function

function F(x: number)
{
    return newFunction(x);
}
function newFunction(x: number)
{
    return x + 1;
}

Notes

  • Extraction is best-effort - the resulting code may not compile or may behave subtly differently.
  • After the refactoring, the caret should be at the beginning of the call to the extracted function.

Extract Constant

Before

const PI = 3.141;
class Circle {
    readonly radius = 3;

    Area() {
        return /*start*/PI * (this.radius ** 2)/*end*/;
    }
}

After - Local

const PI = 3.141;
class Circle {
    readonly radius = 3;

    Area() {
        const newLocal = PI * (this.radius ** 2);

        return newLocal;
    }
}

After - Property

const PI = 3.141;
class Circle {
    readonly radius = 3;

    private readonly newProperty = PI * (this.radius ** 2);

    Area() {
        return this.newProperty;
    }
}

Notes

  • The extracted range must be an expression (exception
  • Extraction is best-effort - the resulting code may not compile or may behave subtly differently. In particular, evaluation order may change.
  • After the refactoring, the caret should be at the beginning of the call to the extracted constant/property.

Annotate with Type from JSDoc

Before

/** @type {number} */
var x;

After

/** @type {number} */
var x: number;

Notes

  • The caret must be on the name of the declaration to be annotated.

Install @types for JS Module

Before

import "left-pad";

After

import "left-pad";

Notes

  • The caret must be on the name of module being imported.
  • No change is made to the source. Instead, the corresponding @types module for the module being imported is installed in the project.
  • The refactoring will not be offered if no corresponding @types module is available.
  • If there is an error, the corresponding code fix will be offered instead.

Convert to Default Import

Before

// @Filename: /a.d.ts
declare const x: number;
export = x;
// @Filename: /b.ts
import * as a from "./a";
// @Filename: /c.ts
import a = require("./a");

After

// @Filename: /a.d.ts
declare const x: number;
export = x;
// @Filename: /b.ts
import a from "./a";
// @Filename: /c.ts
import a from "./a";

Notes

  • Currently this will only activate if --allowSyntheticDefaultImports is enabled.
  • The caret must be on the name of the module being imported.

Code Fixes

Add Missing Member

Before - TS2339

class C {
}

const c = new C();
c.P = 1; // TS2339

After - Property

class C {
    P: number;
}

const c = new C();
c.P = 1;

After - Index Signature

class C {
    [x: string]: number;
}

const c = new C();
c.P = 1;

Before - TS2551

class C {
    Prop1: number;
}

const c = new C();
c.Prop2 = 1; // TS2551

After - Property

class C {
    Prop2: number;
    Prop1: number;
}

const c = new C();
c.Prop2 = 1;

After - Index Signature

class C {
    [x: string]: number;
    Prop1: number;
}

const c = new C();
c.Prop2 = 1;

Notes

  • The receiver must have a class type.

Synthesize Missing super() Call

Before - TS2377

class Base {
}

class Derived extends Base {
    constructor() { //TS2377
    }
}

After

class Base {
}

class Derived extends Base {
    constructor() {
        super();
    }
}

Notes

  • Always calls super() without arguments.

Implement Interface Members

Before - TS2420

interface I {
    X: number
}

class C implements I { //TS2420
}

After

interface I {
    X: number
}

class C implements I {
    X: number;
}

Implement Abstract members from Base Class

Before - TS2515

abstract class A {
    abstract M();
}

class C extends A { //TS2515
}

After

abstract class A {
    abstract M();
}

class C extends A {
    M() {
        throw new Error("Method not implemented.");
    }
}

Before - TS2563

abstract class A {
    abstract M();
}

const c = class C extends A { //TS2563
}

After

abstract class A {
    abstract M();
}

const c = class C extends A {
    M() {
        throw new Error("Method not implemented.");
    }
}

Prepend this. to Member Access

Before - TS2663

class C {
    private x: number;
    Increment() {
        x++; //TS2663
    }
}

After

class C {
    private x: number;
    Increment() {
        this.x++;
    }
}

Change extends to implements

Before - TS2689

interface I {
}

class C extends I { //TS2689
}

After

interface I {
}

class C implements I {
}

Move super() Call Ahead of this Access

Before - TS17009

class Base {
}

class Derived extends Base {
    private x: number;
    constructor() {
        this.x = 1; //TS17009
        super();
    }
}

After

class Base {
}

class Derived extends Base {
    private x: number;
    constructor() {
        super();
        this.x = 1;
    }
}

Suppress JS Diagnostic

Before

// @ts-check

x++;

After - Suppress Single

// @ts-check

// @ts-ignore
x++;

After - Suppress File

// @ts-nocheck


x++;

Correct Misspelled Name

Before - TS2551

class C {
    Prop1: number;
}

const c = new C();
c.Prop2 = 1; // TS2551

After

class C {
    Prop1: number;
}

const c = new C();
c.Prop1 = 1;

Before - TS2552

let variable1 = 1;
variable2++; //TS2552

After

let variable1 = 1;
variable1++;

Notes

  • There are restrictions on what counts as a misspelling - the lengths must match and be greater than 3, etc.

Handle Unused Symbol

Before - TS6133

// { "compilerOptions": { "noUnusedParameters": true } }
function F(x: number) { //TS6133
}

After - Remove Declaration

// { "compilerOptions": { "noUnusedParameters": true } }
function F() {
}

After - Prepend Underscore

// { "compilerOptions": { "noUnusedParameters": true } }
function F(_x: number) {
}

Before - TS6138

// { "compilerOptions": { "noUnusedLocals": true } }
class C {
    constructor(private x: number) { //TS6138
    }
}

After - Remove Declaration

// { "compilerOptions": { "noUnusedLocals": true } }
class C {
    constructor() {
    }
}

After - Prepend Underscore

// { "compilerOptions": { "noUnusedLocals": true } }
class C {
    constructor(private _x: number) {
    }
}

Notes

  • Prepending an underscore to a constructor parameter declaring a property doesn't fix the error.

Rewrite as Indexed Access Type

Before - TS2713

interface I {
    x: number;
}

let z: I.x; //TS2713

After

interface I {
    x: number;
}

let z: I["x"];

Notes

  • Presently, doesn't work for classes.

Convert JSDoc Type to TS Type

Before - TS8020

// { "compilerOptions": {"strictNullChecks": true} }

let x: ?number; //TS8020

After - null

// { "compilerOptions": {"strictNullChecks": true} }

let x: number | null;

After - null, undefined

// { "compilerOptions": {"strictNullChecks": true} }

let x: number | null | undefined;

Notes

  • Not offered in JS files.

Call Decorator Factory Expression

Before - TS1329

// { "compilerOptions": {"experimentalDecorators": true, "target": "es5"} }

function DecoratorFactory() {
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    }
}

class C {
    @DecoratorFactory //TS1329
    M() { }
}

After

// { "compilerOptions": {"experimentalDecorators": true, "target": "es5"} }

function DecoratorFactory() {
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    }
}

class C {
    @DecoratorFactory()
    M() { }
}
  • Improve this Doc
Back to top Generated by DocFX