We have tested TypeScript 4.4 Beta on our TypeScript codebase. Initial results look very promising for an easy upgrade when TypeScript 4.4 is released.
- We did not need any change in our integration code using TypeScript compiler APIs.
- JavaScript output did not change.
- Some of our TypeScript code required changes to make it compile with TypeScript 4.4 Beta. These are explained in detail below.
Impact: Emit
- There were no changes in the JavaScript emit (
target: "esnext").
- There were changes in declaration files for 0.8% of our packages. All of them were changes in the ordering of constituents of a string literal union type. These are harmless.
Impact: Type Checking
| # |
Change |
Release notes |
Packages affected |
Introduced in |
| 1 |
Defaulting to the unknown type in catch variables |
Announced |
25.8% |
#41013 |
| 2 |
this inside object literal type implicitly has type any |
Not announced |
1.6% |
#43898 |
| 3 |
Always-truthy promise checks for object values |
Not announced |
<1% |
#44491 |
| 4 |
Array type cannot be determined |
Not announced |
<1% |
#44762 |
| 5 |
Control flow analysis of aliased conditions |
Announced |
<1% |
#44730 |
| 6 |
Intersecting Record with an object literal type extends the value type |
Not announced |
<1% |
#44512 |
This is a well documented breaking change. It was the most widespread breakage from TypeScript 4.4 Beta in our codebase. For now, we opted out of the feature using useUnknownInCatchVariables: false compiler option in our base configuration. We might investigate an automated fix in the future.
Rest of the type checking errors were observed when running with useUnknownInCatchVariables: false.
2. this inside object literal type implicitly has type any
This change is not included in the release notes. When object literal type is a return type annotation, in TypeScript 4.4 Beta, this no longer refers to function's this. We fixed this issue by referring to this type by name.
declare function foo(this: number): { p: typeof this; };
// ^
// An outer value of 'this' is shadowed by this container.
// 'this' implicitly has type 'any' because it does not have a type annotation.
Playground link
3. Always-truthy promise checks for object values
This change is not included in the release notes. It looks like this is an extension of Always-Truthy Promise Checks that was announced in TypeScript 4.3. These new errors were false positives in our codebase, fix was to use in operator inside the condition to check for the existence of the value.
declare const cache: Record<string, Promise<number>>;
if (cache["key"]) {}
// ^
// This condition will always return true since this 'Promise<number>' is always defined.
// Did you forget to use 'await'?
Playground link
4. Array type cannot be determined
TypeScript 4.4 Beta fails to determine the type of an array in certain cases where it can be determined by TypeScript 4.3. To fix this issue, we added explicit type annotations to the array variables.
function *unique(
first: Iterable<string>
): Iterable<string> {
const array = [];
// ^
// Variable 'array' implicitly has type 'any[]' in some locations where its type cannot be determined.
for (const o of first) {
const shouldYield = !array.some(o2 => o2 === o);
array.push(o);
if (shouldYield) {
yield o;
}
}
}
Playground link
This is a well documented change. It revealed some issues in typings. Manual fixes were trivial.
6. Intersecting Record with an object literal type extends the value type
This change is not included in the release notes. TypeScript 4.4 Beta (correctly) determines the possible value types of the intersection. Manual fixes were trivial.
type Result = { value: string; };
type ResultMap = Record<string, Result> & { count: number };
declare const results: ResultMap;
Object.values(results).forEach((v: Result) => {});
// ^
// Argument of type '(v: Result) => void' is not assignable to parameter of type '(value: number | Result, index: number, array: (number | Result)[]) => void'.
// Type 'number' is not assignable to type 'Result'.
Playground link
If any of these changes do not look intentional/right and should be considered as a bug, I can open issues.
We have tested TypeScript 4.4 Beta on our TypeScript codebase. Initial results look very promising for an easy upgrade when TypeScript 4.4 is released.
Impact: Emit
target: "esnext").Impact: Type Checking
unknowntype in catch variablesthisinside object literal type implicitly has typeanyRecordwith an object literal type extends the value type1. Defaulting to the
unknowntype in catch variablesThis is a well documented breaking change. It was the most widespread breakage from TypeScript 4.4 Beta in our codebase. For now, we opted out of the feature using
useUnknownInCatchVariables: falsecompiler option in our base configuration. We might investigate an automated fix in the future.Rest of the type checking errors were observed when running with
useUnknownInCatchVariables: false.2.
thisinside object literal type implicitly has typeanyThis change is not included in the release notes. When object literal type is a return type annotation, in TypeScript 4.4 Beta,
thisno longer refers to function'sthis. We fixed this issue by referring tothistype by name.Playground link
3. Always-truthy promise checks for object values
This change is not included in the release notes. It looks like this is an extension of Always-Truthy Promise Checks that was announced in TypeScript 4.3. These new errors were false positives in our codebase, fix was to use
inoperator inside the condition to check for the existence of the value.Playground link
4. Array type cannot be determined
TypeScript 4.4 Beta fails to determine the type of an array in certain cases where it can be determined by TypeScript 4.3. To fix this issue, we added explicit type annotations to the array variables.
Playground link
5. Control flow analysis of aliased conditions
This is a well documented change. It revealed some issues in typings. Manual fixes were trivial.
6. Intersecting
Recordwith an object literal type extends the value typeThis change is not included in the release notes. TypeScript 4.4 Beta (correctly) determines the possible value types of the intersection. Manual fixes were trivial.
Playground link
If any of these changes do not look intentional/right and should be considered as a bug, I can open issues.