Repository: TypeScript
Issue: Type Math.min & Math.max using generic
Labels: Suggestion,In Discussion

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Please read the FAQ first, especially the "Common Feature Requests" section.

-->

## Search Terms

<!-- List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily -->
- Math.min generic
- Math.max generic

## Suggestion

<!-- A summary of what you'd like to see added or changed -->

Currently, Math.min is typed as:
```js
min(...values: number[]): number;
```

However, I would like to change the definition to:
```js
min<T extends number>(...values: [T, ...T[]]): T;
min(): number; // Because this will return Infinity
```

Because Math.min should never return things that aren't its input. (Except when non-number is passed in, then it'll return `NaN`. But that's impossible with this typing.)

(Okay, there's another case: if no value is passed in, it'll return `Infinity`. Unfortunately, there's no literal type for `Infinity` so we can't type that correctly. ~And AFAIK there's no way to force at least 1 parameter with rest args.~ **Updated**: there is, using tuple type: `[T, ...T[]]`. Proposal updated. Still, it would be nice to have literal `Infinity` type.)

(The same applies with Math.max, except `Infinity` is now `-Infinity`)

## Use Cases

<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->

Let's say I have this type:
```js
type TBankNoteValues = 1 | 5 | 10 | 20 | 50 | 100;
```

And I want to know what is the highest-value banknote I have in the array. I could use Math.max to find that out. But with the current typing, the return value isn't guaranteed to be TBankNoteValues.

```js
let values: TBankNoteValues[] = [50, 100, 20];
let maxValues = Math.max(...values); // number
```

And now I can't pass maxValues to a function that expects TBankNoteValues anymore.

## Examples

<!-- Show how this would be used and what the behavior would be -->

```js
type TBankNoteValues = 1 | 5 | 10 | 20 | 50 | 100;

let values: TBankNoteValues[] = [50, 100, 20];
let maxValues = Math.max(...values);
// Current type: number
// Expected type: TBankNoteValues
```

[Playground link](https://www.typescriptlang.org/play/index.html#src=type%20TBankNoteValues%20%3D%201%20%7C%205%20%7C%2010%20%7C%2020%20%7C%2050%20%7C%20100%3B%0A%0Alet%20values%3A%20TBankNoteValues%5B%5D%20%3D%20%5B50%2C%20100%2C%2020%5D%3B%0Alet%20maxValues%20%3D%20Math.max(...values)%3B)

## Checklist

My suggestion meets these guidelines:

* [ ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  - ~~Shouldn't be any. Anything that expects the old signature, TypeScript should just infer `T` to `number`.~~
  - Now that I think about it, this make the return type of the function narrows down. So, it could make type inference on a variable declaration changes unexpectedly. An explicit type annotation should fix this.
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).