Typescript: Incorrect (potentially) indentation of function arguments spanning multiple lines

Created on 14 Oct 2016  Β·  17Comments  Β·  Source: microsoft/TypeScript

_From @nomaed on October 14, 2016 10:40_

  • VSCode Version: 1.6.1
  • OS Version: macOS Sierra 10.12

Steps to Reproduce:

  • Write a function (or a method) with several arguments (I did it with JavaScript and TypeScript files, but I believe any would work).
function myFunc(arg1, arg2, arg3, ...args) {
}
  • Split arguments to several lines by hitting Enter before arguments
function myFunc(arg1,
arg2,
arg3,
...args) {
}

Auto-formatting produces this result:

function myFunc(arg1,
    arg2,
    arg3,
    ...args) {
}

I would expect to see this result instead though:

function myFunc(arg1,
                arg2,
                arg3,
                ...args) {
}

Also, when manually formatting the arguments to appear in the same column (note: this is also the default/recommended setting in tslint and maybe other linters), then further lines will start with wrong indentation:

function myFunc(arg1,
                arg2,
                arg3,
                ...args) {
                    console.log('huh...');
}

vscode-multi-line-args-indent

_Copied from original issue: Microsoft/vscode#13748_

Awaiting More Feedback Formatter Suggestion VS Code Tracked

Most helpful comment

My prefered style for large method/function signatures:

class Example {
    public method(
        arg1: string,
        arg2: number,
        arg3: boolean
    ): ReturnType {
        const result = doSomething();
        return new ReturnType(result);
    }
}

All 17 comments

@nomaed thank you for opening this issue.

@dbaeumer can I get some other eyes on this? I think I actually prefer this result with auto formatting:

function myFunc(arg1,
    arg2,
    arg3,
    ...args) {
}

But that might simply be my preference. Possibly there should be an option for OP to customize the auto formatting for his preference?

@bowdenk7 if you have a thought on this too that would be helpful. Don't know if this has come up much in your user studies...

_From @dbaeumer on October 14, 2016 15:4_

@waderyan I prefer yours as well. Agree that this should be a setting in the TS formatter. The good thing is if you formatted it once it will leave it as is.

_From @nomaed on October 14, 2016 15:8_

It definitely shouldn't be the only option. I personally grew to like it a lot (it's the default setting in JetBrains' IDEs) and since it's a default for TSLint (https://github.com/palantir/tslint/blob/master/src/rules/alignRule.ts), I am thinking that it's not uncommon to use this setting.

Moving this to TS language service to address adding the setting. Thank you for your feedback @nomaed. It is valued very highly.

I have a related question about good practice in formatting: what about the returned type? It should be indent, in next line, or how?

class Example {
    public method(arg1: string,
                  arg2: number,
                  arg3: boolean)
                  : ReturnType {
        const result = doSomething();
        return new ReturnType(result);
    }
}

or maybe:

public method(arg1: string,
              arg2: number
              ): ReturnType {
    ...
}

@19majkel94 Option no. 2 probably.
Return type (at last the semicolon) is immediately following the args closing parenthesis, so to make it appear in a new line, the closing parenthesis should be moved down too.

I think that these should all be valid:

/**
* #1
 * If first arg is on the same line as the function decl/name,
 * all args are lined up with the first one.
 */
function funcName(arg1: string,
──────────────────arg2: number,
──────────────────arg3: any): ReturnType {
β‡’   console.log('Hello world');
}

/**
 * #2
 * If first arg is newlined, it is double-indented so it remains 1 indent 
 * level in front of impl., and all args are lined up.
 */
function funcName(
β‡’   β‡’   arg1: string,
β‡’   β‡’   arg2: number,
β‡’   β‡’   arg3: any): ReturnType {
β‡’   console.log('Hello world');
}

/**
 * #3
 * In case first arg is newlined like in #2, allow closing parenthesis
 * to be newlined too (outdent once) with return type following it
 */
function funcName(
β‡’   β‡’   arg1: string,
β‡’   β‡’   arg2: number,
β‡’   β‡’   arg3: any
β‡’   ): ReturnType {
β‡’   console.log('Hello world');
}

The reason why I don't like the way it is now is that the argument aren't aligned and it's decreasing readability.

In case no. 3, the return type indent once is decreasing readability. So I prefer my option no. 2 but it's
sensitive to function rename - we have to indent all again.

My prefered style for large method/function signatures:

class Example {
    public method(
        arg1: string,
        arg2: number,
        arg3: boolean
    ): ReturnType {
        const result = doSomething();
        return new ReturnType(result);
    }
}

I'd like to add that the current indentation rule appear to work incorrectly when combined wth multiple nesting levels. In a naked VSCode install, auto format produces this:

this.client
      .getContinents()
      .subscribe(
      x => this.continents = x,
      e => this.errorMessage = e
      );

instead of:

this.client
      .getContinents()
      .subscribe(
          x => this.continents = x,
          e => this.errorMessage = e
      );

Maybe I am missing something, but my project has the following tslint.json file:

{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {
        "quotemark": [
            "single"
        ],
        "no-console": [
            false
        ],
        "arrow-parens": false,
        "no-string-literal": false,
        "no-namespace": [
            "allow-declarations"
        ],
        "interface-name": [
            "never-prefix"
        ],
        "no-trailing-whitespace": [true, "ignore-comments"]
    },
    "rulesDirectory": []
}

And TSLint does complain about parameters not being aligned after I auto format (using default settings, I am pretty sure since I am not overriding anything with typescript.format).
I know I can turn off TSLint's rule, but I would prefer to control settings for this...
I find what seems the default to not be the most readable option:
screen shot 2017-08-22 at 2 03 33 pm

It would be best to provide a configuration so a user can choose which way to go.

This is still an open issue in VS code 1.30.1 - the TS autoformatter removes leading whitespace, even if the tslint config is:

 "rules": {
    "align": [
      true,
      "parameters",
      "arguments",
      "statements",
      "members",
      "elements"
    ],

The comments above RE "I prefer a single tab indent when continuing the parameter list on a newline" aren't particularly useful - this is still a bug.

What about this issue?

Same problem here.

+1 for adding this formatting option in settings

+1 for this. Just migrating from Intellij to VS Code and this is one of the things that bothers me a lot. There are so many ways to configure the editor, but this simple logic requirement is not configurable. Any progress about that?

FWIW, we have been using prettier now for a couple of years. Really helped with this and other code formatting consistency issues across our teams/products.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartynasZilinskas picture MartynasZilinskas  Β·  3Comments

manekinekko picture manekinekko  Β·  3Comments

remojansen picture remojansen  Β·  3Comments

jbondc picture jbondc  Β·  3Comments

weswigham picture weswigham  Β·  3Comments