You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the only change in declaration output in our codebase. It is not explicitly mentioned in the release notes. It might be possible to handcraft some examples where this could be a breaking change but that is not the case for our codebase. This change looks harmless.
The overall impact of this version is very small and we can proactively update all affected packages in a forward-compatible way. However, we do think that some corner cases are worth looking at as they break here.
This is a documented change that seems to be breaking in very small corner cases.
Here is a first example where Awaited trips up with control flow analysis in TS 4.5 Beta:
declarefunctiondeepEqual<T>(actual: T,expected: T): void;exportasyncfunctiontestRequestSuccess<T>(resultP: Promise<T>,expected: T){letactual;try{actual=awaitresultP;}catch(_e){}// The type parameter of `deepEqual` is inferred based on the first argument.// TypeScript 4.4 calculates `T | undefined`, so passing `expected: T` is okay.// TypeScript 4.5 calculates `Awaited<T> | undefined`, which can't have `T` assigned to it.// Removing the earlier try-catch gets things working because `actual`'s type is just `Awaited<T>`,// which you *can* assign `T` to.deepEqual(actual,expected);}
Some of our projects have the noImplicitAny: false flag set. In this situation, some unwanted inference seems to happen in TS 4.5 Beta:
interfaceRejectedValue{status: "rejected";reason: Error|any;}interfaceFulfilledValue{status: "fulfilled";value: unknown;}typeSettledValue=RejectedValue|FulfilledValue;typeSettledPromises=Promise<SettledValue[]>;// This example requires `"noImplicitAny": false`.exportdefaultfunctionallSettled(promises): SettledPromises{constwrappedPromises=promises.map((p)=>Promise.resolve(p).then((value)=>({status: "fulfilled", value })).catch((reason)=>({status: "rejected", reason })));returnPromise.all(wrappedPromises);// ^ TS2322// Type 'Promise<{ [x: string]: any; }>' is not assignable to type 'SettledPromises'.}
In this example, return value is inferred to have Promise<{ [x: string]: any; }> type. This conflicts with the type annotation.
3. Edge case with generics and indexing
We found an instance where behavior differs from the previous version. The following example is contrived but is extracted from a much larger use case in our codebase.
typeTypesOf<TextendsObject>=T[keyofT]typeMatchingKeys<TextendsRecord<string,any>,Condition>=TypesOf<{[KinkeyofT]: T[K]extendsCondition ? K : never}>exportinterfaceModel{foo: string;bar: Array<string>;}typeExtracted<AextendsArray<any>>=unknown;exportdeclarefunctionextract<MextendsModel,KextendsMatchingKeys<M,Array<any>>>(m: M): Extracted<M[K]>;// ^ TS2344// Type 'M[string]' is not assignable to type 'any[]'.
We will attempt to simplify it in the larger case to avoid this situation. However, this is still a breaking change for this edge case.
Additional Remarks: preserveValueImports
We are attempting to enable a few compiler options around modules that simplify the TS -> JS transform.
In order to do so we attempted to set importsNotUsedAsValues: "error" and preserveValueImports. We already have isolatedModules fully enabled and importsNotUsedAsValues: "error" partially enabled.
40% of our packages are ready for those options as-is while the remaining 60% are at least getting one TS1444 error or more. This is to be expected as many users import a mix of values and types on a single line.
A code fix that is capable of inserting type modifiers where appropriate would be very valuable here. It would turn the following code:
import{value,Type}from"./lib";// ^ TS1444// 'Type' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled.
into
import{value,typeType}from"./lib";// no errors 🎉
If any of these changes do not look intentional/right and should be considered as a bug, we can open issues.
Thanks as always for the detailed feedback! I can chime in on a couple things:
I think “Promise.all overload for any” and “Change of inference with noImplicitAny: false” are in fact the same issue, which is being tracked at #46169.
A code fix that is capable of inserting type modifiers where appropriate would be very valuable here.
I intended to add this codefix when I implemented type-only import specifiers, but must have forgotten. I think we can probably get this in before the RC.
This issue has been created by the team responsible for the infrastructure behind most of Bloomberg's TypeScript code.
We have tested TypeScript 4.5 Beta on our TypeScript codebase. The current results indicate, once again, a fairly easy upgrade.
target: "esnext"
). These are explained in detail below.importsNotUsedAsValues: "error"
,preserveValueImports
andisolatedModules
at the same time.Impact: Emit
Promise.all
overload forany
1. JSX transform spreads children
This is the only change in JavaScript output in our codebase. It is not a breaking change in semantics as
React.createElement
can handle both cases.Playground in TS 4.5 Beta
Playground in TS 4.4.3
2.
Promise.all
overload forany
This is the only change in declaration output in our codebase. It is not explicitly mentioned in the release notes. It might be possible to handcraft some examples where this could be a breaking change but that is not the case for our codebase. This change looks harmless.
Playground in TS 4.5 Beta
Playground in TS 4.4.3
Impact: Type Checking
noImplicitAny: false
The overall impact of this version is very small and we can proactively update all affected packages in a forward-compatible way. However, we do think that some corner cases are worth looking at as they break here.
1. Awaited type & promise signature change
This is a documented change that seems to be breaking in very small corner cases.
Here is a first example where
Awaited
trips up with control flow analysis in TS 4.5 Beta:Playground in TS 4.4.3 | Playground in TS 4.5 Beta
Additionally, the change in type signature of
Promise
has brought up another issue with an explicitPromise.all
typing:Playground in TS 4.4.3 | Playground in TS 4.5 Beta
Given the low prevalence of those use cases, we can easily convert them to the new form:
Playground in TS 4.5 Beta
2. Change of inference with
noImplicitAny: false
Some of our projects have the
noImplicitAny: false
flag set. In this situation, some unwanted inference seems to happen in TS 4.5 Beta:Playground in TS 4.4.3 | Playground in TS 4.5 Beta
In this example, return value is inferred to have
Promise<{ [x: string]: any; }>
type. This conflicts with the type annotation.3. Edge case with generics and indexing
We found an instance where behavior differs from the previous version. The following example is contrived but is extracted from a much larger use case in our codebase.
Playground in TS 4.4.3 | Playground in TS 4.5 Beta
We will attempt to simplify it in the larger case to avoid this situation. However, this is still a breaking change for this edge case.
Additional Remarks:
preserveValueImports
We are attempting to enable a few compiler options around modules that simplify the TS -> JS transform.
In order to do so we attempted to set
importsNotUsedAsValues: "error"
andpreserveValueImports
. We already haveisolatedModules
fully enabled andimportsNotUsedAsValues: "error"
partially enabled.40% of our packages are ready for those options as-is while the remaining 60% are at least getting one
TS1444
error or more. This is to be expected as many users import a mix of values and types on a single line.type
Modifiers on Import Names will be helpful to resolve those errors and promote those options further.A code fix that is capable of inserting
type
modifiers where appropriate would be very valuable here. It would turn the following code:into
If any of these changes do not look intentional/right and should be considered as a bug, we can open issues.
Credits to @scottrobertwhittaker, @rricard, @tchetwin and @robpalme for helping with this write up.
The text was updated successfully, but these errors were encountered: