Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Function Signature Syntax #29019

Closed
Enteleform opened this issue Dec 14, 2018 · 8 comments
Closed

Improve Function Signature Syntax #29019

Enteleform opened this issue Dec 14, 2018 · 8 comments
Labels
Duplicate An existing issue was already created

Comments

@Enteleform
Copy link

Enteleform commented Dec 14, 2018

Suggestion

Please reconsider combining default parameters & type annotations in function signatures. This was already proposed in #7576, but the issue was closed shortly after @mhegazy's post which made the following argument:

ultimately, every new syntax added is added complexity, for the user to learn and recognize, and for the compiler code base to maintain, so usually we try to limit complexity unless the value warrants it. and for destructuring, the syntax is already complex to start with, and we did not want to add yet another layer on top.

However, in reality the current syntax is more difficult to write & maintain than the proposed syntax. I'd argue that the proposed syntax would even be worth admitting into Breaking Changes in the long run, given that the change is timed & documented appropriately (even if that means waiting for a major version release).

Examples

//####################//
//###  Assertions  ###//
//####################//

                  //  [arg_1, arg_2, arg_3]
  foo()           //  [0,     0,     0    ]
  foo({})         //  [0,     0,     0    ]
  foo({arg_1:1})  //  [1,     0,     0    ]
  
  
//#####################################//
//###  Proposed Function Signature  ###//
//#####################################//

  // easy to parse
  // easy to maintain
  
    function foo({arg_1:number=0, arg_2:number=0, arg_3:number=0}){
      // ...
    }
    
    function foo({
      arg_1: number = 0,
      arg_2: number = 0,
      arg_3: number = 0,
    }){
      // ...
    }


//####################################//
//###  Current Function Signature  ###//
//####################################//
  
  // difficult to parse
  // difficult to maintain (redundant code)
    
    function foo({arg_1=0, arg_2=0, arg_3=0}:{arg_1?:number, arg_2?:number, arg_3?:number}={}){
      // ...
    }
      
    function foo(
      {arg_1=0, arg_2=0, arg_3=0}
      :{arg_1?:number, arg_2?:number, arg_3?:number}
      ={}
    ){
      // ...
    }
  
  
  // ok to parse
  // difficult to maintain (redundant code, formatting is time consuming)
  
    function foo(
      {arg_1=0,       arg_2=0,       arg_3=0      }:
      {arg_1?:number, arg_2?:number, arg_3?:number}={}
    ){
      // ...
    }


  // ok to parse
  // difficult to maintain (redundant code)
  // 
  // This is currently the most balanced option for [writability, readability, maintainability],
  // but results in double the lines of code; which quickly adds up to 100s or 1000s
  // of lines of unnecessary code in a larger project. This boilerplate creates extra work
  // & detracts from TypeScript's developer experience by forcing developers to spend extra time
  // crafting & tweaking function signatures instead of writing more pertinent code.
  
    function foo({
      arg_1 = 0,
      arg_2 = 0,
      arg_3 = 0,
    }:{
      arg_1?: number,
      arg_2?: number,
      arg_3?: number,
    }={}){
      // ...
    }

Note

A few people have mentioned that there may be a conflict with the {a:b=c} syntax. However, the exact syntax is not the purpose of this recommendation, and I invite any suggestions for a more preferable syntax that does not have any compatibility issues. The important part of this suggestion is that the syntax should be able to handle type annotations & default parameters in one section instead of two.

Search Terms

destructuring destructure function signature default parameters type annotations

@dmytro-lymarenko
Copy link

Why not this:

interface FooArgs {
	arg_1?: number;
	arg_2?: number;
	arg_3?: number;
}

function foo(arg: FooArgs) {
	const { arg_1 = 0, arg_2 = 0, arg_3 = 0 } = arg;
}

?

@dmytro-lymarenko
Copy link

dmytro-lymarenko commented Dec 14, 2018

Plus, this syntax

{ arg_1: number = 0 }

means that you rename arg_1 to number and set its initial value to 0

@Enteleform
Copy link
Author

Enteleform commented Dec 14, 2018

@dmytro-lymarenko

interface FooArgs {
	arg_1?: number;
	arg_2?: number;
	arg_3?: number;
}

function foo(arg: FooArgs) {
	const { arg_1 = 0, arg_2 = 0, arg_3 = 0 } = arg;
}

has the same issue as mentioned in the OP.

 
It would be much more concise as

function foo({arg_1:number=0, arg_2:number=0, arg_3:number=0}){
}

which eliminates code duplication.
 


 
Regarding the potential syntax conflict you brought up:
{arg_1: number = 0}

I'm not sure that the assignment syntax directly conflicts with the function signature syntax. Even if it does, the syntax I proposed is definitely open to adjustment. The main point is to reduce excess/duplicate code.

This could just as easily be accomplished with

foo({{arg_1: number = 0}})
foo({<number> arg_1 = 0})

or some other similar, non-conflicting syntax.

@j-oliveras
Copy link
Contributor

As @dmytro-lymarenko said: the proposed syntax collides with javascript rename on destructuring arguments (using this example: function foo({arg_1:number=0}) {} is put into a variable named number the value of the property named args_1 from the first parameter, if that property not exists use 0.

This proposed

function foo({arg_1:number=0, arg_2:number=0, arg_3:number=0}){
}

has the problem that all there values must be stored to the same variable as you can see into playground.

@Enteleform
Copy link
Author

Enteleform commented Dec 14, 2018

@j-oliveras

I addressed that issue in the second half of my response to @dmytro-lymarenko. The *exact* syntax that I proposed is not important, it can definitely be altered as needed to make it work.

@weswigham weswigham added the Duplicate An existing issue was already created label Dec 14, 2018
@weswigham
Copy link
Member

weswigham commented Dec 14, 2018

Still a dupe of #7576 and it's still declined for all the same reasons.

@Enteleform
Copy link
Author

@weswigham

I'd argue that it should be reconsidered/reopened, especially when considering the related issue in #5326. If these issues are not handled properly, then TypeScript's signatures will become even more redundant and troublesome to maintain than they already are. Also, this is clearly something that users want, as noted by the continued activity in #7576 after it was closed. Multiple users have even commented that they avoid using destructuring and/or TypeScript altogether because of these issues. The initial specification was designed poorly, and it should be rectified rather than implementing clumsy workarounds every time a new feature needs to be added.

Breaking changes have been made for certain features, and I think that solving the cluttered function signature issues that currently exist would be worthy of a breaking change. Having a single-section function signature would then allow all future changes to be implemented much more easily.

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants