Typescript: Optional Arguments

Created on 8 May 2019  ·  4Comments  ·  Source: microsoft/TypeScript

Search Terms


Optional Arguments
Optional Parameters

Suggestion


It would be really nice to have the ability to make optional parameters skippable if the type of that parameter is given.

async delete(reason?: string, seconds = 0, force = false) {
  // some stuff here using those args to delete something
}

In this function, everything is typed appropriately and can be easily distinguishes that X value will be given to Y parameter.

If each parameter type is unique and no parameters have any then a value can easily be understood that this value is meant for x parameter.

Use Cases


This would fix a lot of annoying, tedious, and redundant function calls.

Currently

// To delete with a reason
this.delete('Typescript is Love! Typescript is Life! TS WIN!')

// To delete with no reason but with a time.
this.delete('', 5000)

// To force delete something
this.delete('', 0, true)

Examples

// Delete with a timer
this.delete(5000)

// To force delete something
this.delete(true)

// I could even do wrong order(although bad practice tbh)
// it could still pass because types are powerful
this.delete(false, 5000, 'some string')

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, etc.)
  • [ ] This feature would agree with the rest of TypeScript's Design Goals.
Out of Scope

Most helpful comment

This'd need type directed emit, which we won't do. You should -really_ just be using the option-bag pattern in these cases, eg:

async function del({ reason = undefined as string | undefined, seconds = 0, force = false }) {
    // some stuff here using those args to delete something
}

// To delete with a reason
del({reason: 'Typescript is Love! Typescript is Life! TS WIN!'})

// To delete with no reason but with a time.
del({reason: '', seconds: 5000})

// To force delete something
del({reason: '', seconds: 0, force: true})

// Delete with a timer
del({seconds: 5000})

// To force delete something
del({force: true})

// I could even do wrong order(although bad practice tbh)
// it could still pass because types are powerful
del({force: false, seconds: 5000, reason: 'some string'})

All 4 comments

While this would be nice, it 1) falls under the purview of “type-directed emit” which TS explicitly doesn’t do and 2) makes the same call site potentially mean something different in TypeScript than it would in plain JS.

See Non-Goal # 5:

[Do not] Add or rely on run-time type information in programs, or emit different code based on the results of the type system. Instead, encourage programming patterns that do not require run-time metadata.

That's what overloads are for.

Seems to me your asking for a special transform plugin, to handle this?
Doing it manually..
Overloads and/or rest params with tuples.

 const delete = <
  T extends
    | [string]
    | [string, number]
    | [string, number, boolean]
    | [number]
    | [boolean]
>(
  ...args: T
)=>{
//handle args assignments inside to correctly assign params
    // some stuff here using those args to delete something
  };

or destructure parms with object?

This'd need type directed emit, which we won't do. You should -really_ just be using the option-bag pattern in these cases, eg:

async function del({ reason = undefined as string | undefined, seconds = 0, force = false }) {
    // some stuff here using those args to delete something
}

// To delete with a reason
del({reason: 'Typescript is Love! Typescript is Life! TS WIN!'})

// To delete with no reason but with a time.
del({reason: '', seconds: 5000})

// To force delete something
del({reason: '', seconds: 0, force: true})

// Delete with a timer
del({seconds: 5000})

// To force delete something
del({force: true})

// I could even do wrong order(although bad practice tbh)
// it could still pass because types are powerful
del({force: false, seconds: 5000, reason: 'some string'})
Was this page helpful?
0 / 5 - 0 ratings