Description
Suggestion
π Search Terms
for..in iterator typing cast coertion
β 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
Because of the flexibility of javascript, typescript can only safely infer object keys as strings, although in most cases a more precise type is what makes sense. Currently there are several workarounds, but all of the ways I can think of are too verbose and emit unnecessary runtime code.
I propose to introduce a syntax to restrict the type of the for..in variable:
for(let iterator as KeyType in iterable)
The as
underlined the fact that it is an unsafe cast, but the syntax is compact.
π Motivating Example
Consider this example using this feature:
interface Data { a?: number, b?: number, c?: number }
function copy(data: Data) {
const out: Data = {};
for(const key as keyof Data in data)
out[key] = data[key]
return out;
}
π» Use Cases
Currently, the example above can be implemented using a duplicate variable:
interface Data { a?: number, b?: number, c?: number }
function copy(data: Data) {
const out: Data = {};
for(const key in data) {
const k = key as keyof Data;
out[k] = data[k];
}
return out;
}
Or the iterator may be coerced to a narrower type using an assertion:
interface Data { a?: number, b?: number, c?: number }
function castKey<T>(key: PropertyKey): asserts key is keyof T {}
function copy(data: Data) {
const out: Data = {};
for(const key in data) {
castKey<Data>(key);
out[key] = data[key];
}
return out;
}
In both case, the code is rather verbose and arguably a bit technical for the second one, considering this is a rather common use-case. Also some unnecessary js code will be emitted, although it probably has negligible performance impact, I still find it would be cleaner to address this at the typescript level.