TypeScript 2.4
Dynamic Import Expressions
Dynamicimport expressions are a new feature and part of ECMAScript that allows users to asynchronously request a module at any arbitrary point in your program.
This means that you can conditionally and lazily import other modules and libraries.For example, here’s anasync function that only imports a utility library when it’s needed:
tsasyncfunctiongetZipFile(name:string,files:File[]):Promise<File> {constzipUtil =awaitimport("./utils/create-zip-file");constzipContents =awaitzipUtil.getContentAsBlob(files);returnnewFile(zipContents,name);}
Many bundlers have support for automatically splitting output bundles based on theseimport expressions, so consider using this new feature with theesnext module target.
String Enums
TypeScript 2.4 now allows enum members to contain string initializers.
tsenumColors {Red ="RED",Green ="GREEN",Blue ="BLUE"}
The caveat is that string-initialized enums can’t be reverse-mapped to get the original enum member name.In other words, you can’t writeColors["RED"] to get the string"Red".
Improved inference for generics
TypeScript 2.4 introduces a few wonderful changes around the way generics are inferred.
Return types as inference targets
For one, TypeScript can now make inferences for the return type of a call.This can improve your experience and catch errors.Something that now works:
tsfunctionarrayMap<T,U>(f: (x:T)=>U): (a:T[])=>U[] {returna=>a.map(f);}constlengths: (a:string[])=>number[] =arrayMap(s=>s.length);
As an example of new errors you might spot as a result:
tsletx:Promise<string> =newPromise(resolve=> {resolve(10);// ~~ Error!});
Type parameter inference from contextual types
Prior to TypeScript 2.4, in the following example
tsletf: <T>(x:T)=>T =y=>y;
y would have the typeany.This meant the program would type-check, but you could technically do anything withy, such as the following:
tsletf: <T>(x:T)=>T =y=>y() +y.foo.bar;
That last example isn’t actually type-safe.
In TypeScript 2.4, the function on the right side implicitlygains type parameters, andy is inferred to have the type of that type-parameter.
If you usey in a way that the type parameter’s constraint doesn’t support, you’ll correctly get an error.In this case, the constraint ofT was (implicitly){}, so the last example will appropriately fail.
Stricter checking for generic functions
TypeScript now tries to unify type parameters when comparing two single-signature types.As a result, you’ll get stricter checks when relating two generic signatures, and may catch some bugs.
tstypeA = <T,U>(x:T,y:U)=> [T,U];typeB = <S>(x:S,y:S)=> [S,S];functionf(a:A,b:B) {a =b;// Errorb =a;// Ok}
Strict contravariance for callback parameters
TypeScript has always compared parameters in a bivariant way.There are a number of reasons for this, but by-and-large this was not been a huge issue for our users until we saw some of the adverse effects it had withPromises andObservables.
TypeScript 2.4 introduces tightens this up when relating two callback types. For example:
tsinterfaceMappable<T> {map<U>(f: (x:T)=>U):Mappable<U>;}declareleta:Mappable<number>;declareletb:Mappable<string |number>;a =b;b =a;
Prior to TypeScript 2.4, this example would succeed.When relating the types ofmap, TypeScript would bidirectionally relate their parameters (i.e. the type off).When relating eachf, TypeScript would also bidirectionally relate the type ofthose parameters.
When relating the type ofmap in TS 2.4, the language will check whether each parameter is a callback type, and if so, it will ensure that those parameters are checked in a contravariant manner with respect to the current relation.
In other words, TypeScript now catches the above bug, which may be a breaking change for some users, but will largely be helpful.
Weak Type Detection
TypeScript 2.4 introduces the concept of “weak types”.Any type that contains nothing but a set of all-optional properties is considered to beweak.For example, thisOptions type is a weak type:
tsinterfaceOptions {data?:string;timeout?:number;maxRetries?:number;}
In TypeScript 2.4, it’s now an error to assign anything to a weak type when there’s no overlap in properties.For example:
tsfunctionsendMessage(options:Options) {// ...}constopts = {payload:"hello world!",retryOnFail:true};// Error!sendMessage(opts);// No overlap between the type of 'opts' and 'Options' itself.// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'.
You can think of this as TypeScript “toughening up” the weak guarantees of these types to catch what would otherwise be silent bugs.
Since this is a breaking change, you may need to know about the workarounds which are the same as those for strict object literal checks:
- Declare the properties if they really do exist.
- Add an index signature to the weak type (i.e.
[propName: string]: {}). - Use a type assertion (i.e.
opts as Options).
The TypeScript docs are an open source project. Help us improve these pagesby sending a Pull Request ❤
Last updated: Dec 16, 2025