Skip to content

Infer array as tuple when used as rest argument in a complex expression #56765

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

Open
6 tasks done
matthieusieben opened this issue Dec 13, 2023 · 3 comments
Open
6 tasks done
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@matthieusieben
Copy link

matthieusieben commented Dec 13, 2023

πŸ” Search Terms

"infer rest array type"
"infer rest array args"
"infer rest array tuple"
"spread argument array expression "

βœ… Viability Checklist

⭐ Suggestion

Given the following function

function foo (a: number, b: string, c: boolean) {}

TypeScript already supports inferring that an array used as rest argument should be considered as a tuple:

foo (1, ...(["a", true])) // Works

But if you add some condition to the mix, type inference breaks:

const someCondition = true

foo (1, ...(someCondition ? ["a", true] : ['b', false])) // A spread argument must either have a tuple type or be passed to a rest parameter.(2556)

My suggestion it to add support for inlined array inside complex expression to be used as spread args.

Playground link

πŸ“ƒ Motivating Example

I came accros this issue while designing a database agnostic module based on kysely.

I used to write stuff like so:

const myTableWithId =
  dialect === 'pg'
    ? db.schema
        .createTable('my_table')
        .addColumn('id', 'bigserial', (col) => col.primaryKey())
    : db.schema
        .createTable('my_table')
        .addColumn('id', 'bigint', (col) => col.autoIncrement().primaryKey())

await myTableWithId
  .addColumn('my_col', 'varchar', (col) => col.notNullable())
  .execute()

But this breaks the linear style of the definition. The following notation is more natural:

await db.schema
  .createTable('oauth_device')
  .addColumn(
    'id',
    ...(dialect === 'pg'
      ? ['bigserial', (col) => col.primaryKey()]
      : ['bigint', (col) => col.autoIncrement().primaryKey()])
  )
  .addColumn('my_col', 'varchar', (col) => col.notNullable())
  .execute()

It currently work but requires additional typecasting (see playground link before)

πŸ’» Use Cases

  1. What do you want to use this for? Be able to write more readable code
  2. What shortcomings exist with current approaches? Unnecessarily more verbose
  3. What workarounds are you using in the meantime? Declare the type of the spread tuple and cast every value to that type
@Andarist
Copy link
Contributor

Some issues that are likely related in some ways:
#45600
#42508
#42037

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases labels Dec 13, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Dec 13, 2023
@RyanCavanaugh
Copy link
Member

The specific case of a ternary seems OK to try adding

@StevenJL
Copy link

This would be very nice to add.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

No branches or pull requests

4 participants