microsoft / microsoft/TypeScript
Evaluate mathematical expression of indices when indexing tuples
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
Suggestion
🔍 Search Terms
tuple bounds, tuple index computing, bound checking removal, noUncheckedIndexedAccess
✅ 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
Currently (version 4.1), Typescript is able to deduce that an array access to a tuple is within bounds if it is indexed by an integer literal union type that fits within the array, e.g.:
type I = 0 | 1 | 2;
function access(i: I, a: [string, string, string]) {
return a[i];
} // type: string, even with noUncheckedIndexedAccess = true
However, as soon as there is an operation on the indexing variable, even trivial, Typescript falls back to inferring number. Therefore, the following code:
type I = 0 | 1;
function access(i: I, a: [string, string, string]) {
return a[i + 1];
} // type: string | undefined, when noUncheckedIndexedAccess = true
In principle, Typescript could reason a bit deeper on the set of possible integer values when going through operations, especially for the trivial ones like in my example. If there is a lot of values in the union, it might be computationally expensive, but in that case a conservative bound analysis would already be enough for most uses cases (see #15480).
📃 Motivating Example
The proposed feature would at minimum allow:
type I = 0 | 1;
function access(i: I, a: [string, string, string]) {
return a[i + 1];
}
and, if possible, use cases such as:
type Vector = [number, number];
type Matrix = [number, number, number, number];
const Range = [0, 1] as const;
function mult(m: Matrix, v: Vector) {
let ret: Vector = [0, 0];
for (const i of Range) {
let acc = 0;
for (const j of Range) {
acc += v[j] * m[i * 2 + j];
}
ret[i] = acc;
}
return ret;
}
and, if Vector and Matrix can be aliases to fixed-size typed arrays (see #18471) in addition to tuple, it would be wonderful.
💻 Use Cases
That feature would be very useful in conjunction with noUncheckedIndexedAccess obviously, but also with a way to statically type the length of TypedArray (see #18471) for use in mathematical and graphics code. But even without typed arrays, it would still be useful in day-to-day code. I'm experimenting in switching our 45 kloc Typescript code base to noUncheckedIndexedAccess = true and that feature would increase type safety in several places.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review the tuple-indexing examples and the related discussions in #15480 and #18471 first. Then trace the TypeScript type-checking behavior for tuple accesses under noUncheckedIndexedAccess and determine how the shown expressions should be validated. Done should include the motivating examples producing the intended non-undefined types without changing emitted JavaScript.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100