Skip to content

Check argument names in function callsΒ #46455

Closed as not planned
Closed as not planned
@Finesse

Description

@Finesse

Suggestion

πŸ” Search Terms

  • named arguments
  • name argument function call
  • hide property name
  • hide attribute name
  • remove property name

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

This suggestion is very similar to #467, but it has another purpose and motivation.

I'd like to have an ability to specify argument names in function calls. TypeScript will emit an error if an argument name in a function call expression doesn't match the argument name in the function declaration.

function foo(name: string, surname: string) {}

foo(surname: 'Doe', name: 'John'); // error, both the argument names don't match
foo(foo: 'John', bar: 'Doe'); // error
foo(name: 'John', surname: 'Doe'); // ok
foo('John', 'Doe'); // ok, argument names are optional
foo(name: 'John', 'Doe'); // ok
foo('Doe', name: 'John'); // error, the second argument name doesn't match

TypeScript compiler will just remove the argument names from the function invocation expressions. The argument names in call expressions don't affect the output code at all.

This idea can be spread further on arrays with named elements, but this is off-topic here.

πŸ“ƒ Motivating Example

The motivation is a need to hide my source code. Let's say I use TypeScript with Terser, I need to make a function with many arguments and hide the argument names from the output code.

The following source code will give the result I want:

function secretFunctionName(
  secretName: string,
  anotherSecretName: string,
  yetAnotherSecretName: string,
  theMostSecretName: string
) {
    return [secretName, anotherSecretName, yetAnotherSecretName, theMostSecretName].join();
}

console.log(secretFunctionName('foo', 'bar', 'baz', 'baq'));
console.log(secretFunctionName('1', '2', '3', '4'));

// TypeScript + Terser output:
function o(o,n,l,a){return[o,n,l,a].join()}
console.log(o("foo","bar","baz","baq"));
console.log(o("1","2","3","4"));

But it's prone to human mistake because all the arguments have the same type so there will be no TypeScript error if a pair of arguments in a function call is swapped.

A common solution for such mistakes is passing arguments in an object:

interface Arguments {
  secretName: string,
  anotherSecretName: string,
  yetAnotherSecretName: string,
  theMostSecretName: string
}

function secretFunctionName({
  secretName,
  anotherSecretName,
  yetAnotherSecretName,
  theMostSecretName
}: Arguments) {
    return [secretName, anotherSecretName, yetAnotherSecretName, theMostSecretName].join();
}

console.log(secretFunctionName('foo', 'bar', 'baz', 'baq'));
console.log(secretFunctionName('1', '2', '3', '4'));

// TypeScript + Terser output:
function e({secretName:e,anotherSecretName:t,yetAnotherSecretName:r,theMostSecretName:m}){return[e,t,r,m].join()}
console.log(e({secretName:"foo",anotherSecretName:"bar",yetAnotherSecretName:"baz",theMostSecretName:"baq"}));
console.log(e({secretName:"1",anotherSecretName:"2",yetAnotherSecretName:"3",theMostSecretName:"4"}));

That it, the secret argument names have got to the output code. Also, the output code is much bigger.

The syntax I suggest will solve both problems (will conceal the argument names and help preventing human mistakes):

function secretFunctionName(
  secretName: string,
  anotherSecretName: string,
  yetAnotherSecretName: string,
  theMostSecretName: string
) {
    return [secretName, anotherSecretName, yetAnotherSecretName, theMostSecretName].join();
}

console.log(secretFunctionName(
  secretName: 'foo',
  anotherSecretName: 'bar',
  yetAnotherSecretName: 'baz',
  theMostSecretName: 'baq'
));
console.log(secretFunctionName(
  secretName: '1',
  anotherSecretName: '2',
  yetAnotherSecretName: '3',
  theMostSecretName: '4'
));

// TypeScript + Terser output:
function o(o,n,l,a){return[o,n,l,a].join()}
console.log(o("foo","bar","baz","baq"));
console.log(o("1","2","3","4"));

πŸ’» Use Cases

Besides concealing the source code, the new syntax will help producing smaller JS scripts. Developers will achieve it by replacing argument objects with regular arguments and function call checks.

At the moment I can solve my issue by taking a risk of mistakes by using regular arguments as shown in the first code snippet in the "Motivating Example" section.

Another solution is using an argument object with a const enum which is bulky:

const enum ArgumentName {
  Secret,
  AnotherSecret,
  YetAnotherSecret,
  TheMostSecret
}

interface Arguments {
  [ArgumentName.Secret]: string,
  [ArgumentName.AnotherSecret]: string,
  [ArgumentName.YetAnotherSecret]: string,
  [ArgumentName.TheMostSecret]: string
}

function secretFunctionName(args: Arguments) {
    return [
      args[ArgumentName.Secret],
      args[ArgumentName.AnotherSecret],
      args[ArgumentName.YetAnotherSecret],
      args[ArgumentName.TheMostSecret]
    ].join();
}

console.log(secretFunctionName({
  [ArgumentName.Secret]: 'foo',
  [ArgumentName.AnotherSecret]: 'bar',
  [ArgumentName.YetAnotherSecret]: 'baz',
  [ArgumentName.TheMostSecret]: 'baq'
}));
console.log(secretFunctionName({
  [ArgumentName.Secret]: '1',
  [ArgumentName.AnotherSecret]: '2',
  [ArgumentName.YetAnotherSecret]: '3',
  [ArgumentName.TheMostSecret]: '4'
}));

// TypeScript + Terser output:
function o(o){return[o[0],o[1],o[2],o[3]].join()}
console.log(o({0:"foo",1:"bar",2:"baz",3:"baq"}));
console.log(o({0:"1",1:"2",2:"3",3:"4"}));

Metadata

Metadata

Assignees

No one assigned

    Labels

    Out of ScopeThis idea sits outside of the TypeScript language design constraintsSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions