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 are supported as of Visual Studio 2017 version 15.0.0.
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.
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.
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.
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.
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.
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.
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.
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.
Before - TS2420
interface I {
X: number
}
class C implements I { //TS2420
}
After
interface I {
X: number
}
class C implements I {
X: number;
}
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.");
}
}
Before - TS2662
- For static members
class C {
static m() { C.m(); }
n() { m(); }
}
After
class C {
static m() { C.m(); }
n() { C.m(); }
}
Before - TS2663
class C {
private x: number;
Increment() {
x++; //TS2663
}
}
After
class C {
private x: number;
Increment() {
this.x++;
}
}
Before - TS2689
interface I {
}
class C extends I { //TS2689
}
After
interface I {
}
class C implements I {
}
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;
}
}
Before
// @ts-check
x++;
After - Suppress Single
// @ts-check
// @ts-ignore
x++;
After - Suppress File
// @ts-nocheck
x++;
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.
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.
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.
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.
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() { }
}
Before - TS1219
// @Filename: /dir/a.ts
declare const decorator: any;
class A {
@decorator method() {};
};
// @Filename: /dir/tsconfig.json
{
"compilerOptions": {
}
}
After
// @Filename: /dir/a.ts
declare const decorator: any;
class A {
@decorator method() {};
};
// @Filename: /dir/tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
}
}
Notes
- Experimental support for decorators is a feature that is subject to change in a future release.
Before - TS1308
function f() {
await Promise.resolve();
}
After
async function f() {
await Promise.resolve();
}
Before - TS2724
// @Filename: file1.ts
export const fooooooooo = 1;
// @Filename: file2.ts
import {fooooooooa} from "./file1"; fooooooooa;
After
// @Filename: file1.ts
export const fooooooooo = 1;
// @Filename: file2.ts
import {fooooooooo} from "./file1"; fooooooooa;
Before - TS7027
function f() {
return 1;
return 2;
}
After
function f() {
return 1;
}
Before - TS80005
const a = require("a");
After
import a = require("a");
Before - TS1340
declare module "foo" {
const a = "foo"
export = a
}
const x: import("foo") = import("foo");
After
declare module "foo" {
const a = "foo"
export = a
}
const x: typeof import("foo") = import("foo");
Before - TS7028
label1: while (1) {}
After
while (1) {}
Before - TS1337
type K = "foo" | "bar";
interface SomeType {
a: string;
[prop: K]: any;
}
After
type K = "foo" | "bar";
type SomeType = {
[prop in K]: any;
} & {
a: string;
};
Before - TS2348
class C {
}
var c = C();
After
class C {
}
var c = new C();
Before - TS2352
const s1 = 1 as string;
const o1 = s + " word" as object;
const s2 = <string>2;
const o2 = <object>s2;
After
const s1 = 1 as unknown as string;
const o1 = s + " word" as unknown as object;
const s2 = <string><unknown>2;
const o2 = <object><unknown>s2;
Before - TS7051
var x: (number) => string;
After
var x: (arg0: number) => string;