Bug Report
I ran into this issue while testing my code with the new TS 4.7 beta. I didn't see anything in the breaking changes that looked related, so here's an issue!
🔎 Search Terms
🕗 Version & Regression Information
- This changed between versions 4.6.2 and 4.7.0-beta
⏯ Playground Link
Playground Link: 4.7.0-dev showing the error and 4.6.2 not showing an error.
💻 Code
interface Bounds {
min: number;
max: number;
}
/**
* A version of T where number-valued properties become Bounds-valued properties and all other
* properties are dropped, e.g. NumericBoundsOf<{a: number, b: string}> = {a: Bounds}.
*/
type NumericBoundsOf<T> = {
[K in keyof T as T[K] extends number | undefined ? K : never]: Bounds;
}
// Works as intended:
type X = NumericBoundsOf<{a: number; b: string}>;
// ^? type X = { a: Bounds; }
function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
for (const [key, val] of Object.entries(obj)) {
const boundsForKey = bounds[key as keyof NumericBoundsOf<T>];
if (boundsForKey) {
const {min, max} = boundsForKey;
if (min > val || max < val) return false;
}
}
return true;
}
Output
"use strict";
function validate(obj, bounds) {
for (const [key, val] of Object.entries(obj)) {
const boundsForKey = bounds[key];
if (boundsForKey) {
const { min, max } = boundsForKey;
if (min > val || max < val)
return false;
}
}
return true;
}
Compiler Options
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2017",
"jsx": "react",
"module": "ESNext",
"moduleResolution": "node"
}
}
🙁 Actual behavior
This code fails to type check in TypeScript 4.7.0-beta:
function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
for (const [key, val] of Object.entries(obj)) {
const boundsForKey = bounds[key as keyof NumericBoundsOf<T>];
if (boundsForKey) {
const {min, max} = boundsForKey;
// ~~~ Property 'min' does not exist on type 'unknown'. ts(2339)
// ~~~ Property 'max' does not exist on type 'unknown'. ts(2339)
if (min > val || max < val) {
return false;
}
}
}
return true;
}
It does pass the type checker in TS 4.6.2, as I believe it should.
🙂 Expected behavior
boundsForKey should have a type of Bounds and this should pass the type checker (as it does in TS 4.6.2).
The type of boundsForKey is displayed as NumericBoundsOf<T>[keyof NumericBoundsOf<T>] in both versions, but evidently TS 4.7.0-beta resolves this to unknown whereas TS 4.6.2 resolved it to Bounds.
Bug Report
I ran into this issue while testing my code with the new TS 4.7 beta. I didn't see anything in the breaking changes that looked related, so here's an issue!
🔎 Search Terms
🕗 Version & Regression Information
⏯ Playground Link
Playground Link: 4.7.0-dev showing the error and 4.6.2 not showing an error.
💻 Code
Output
Compiler Options
{ "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictPropertyInitialization": true, "strictBindCallApply": true, "noImplicitThis": true, "noImplicitReturns": true, "alwaysStrict": true, "esModuleInterop": true, "declaration": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, "target": "ES2017", "jsx": "react", "module": "ESNext", "moduleResolution": "node" } }🙁 Actual behavior
This code fails to type check in TypeScript 4.7.0-beta:
It does pass the type checker in TS 4.6.2, as I believe it should.
🙂 Expected behavior
boundsForKeyshould have a type ofBoundsand this should pass the type checker (as it does in TS 4.6.2).The type of
boundsForKeyis displayed asNumericBoundsOf<T>[keyof NumericBoundsOf<T>]in both versions, but evidently TS 4.7.0-beta resolves this tounknownwhereas TS 4.6.2 resolved it toBounds.