TypeScript 3.2
strictBindCallApply
TypeScript 3.2 introduces a newstrictBindCallApply compiler option (in thestrict family of options) with which thebind,call, andapply methods on function objects are strongly typed and strictly checked.
tsfunctionfoo(a:number,b:string):string {returna +b;}leta =foo.apply(undefined, [10]);// error: too few argumentsletb =foo.apply(undefined, [10,20]);// error: 2nd argument is a numberletc =foo.apply(undefined, [10,"hello",30]);// error: too many argumentsletd =foo.apply(undefined, [10,"hello"]);// okay! returns a string
This is achieved by introducing two new types,CallableFunction andNewableFunction, inlib.d.ts. These types contain specialized generic method declarations forbind,call, andapply for regular functions and constructor functions, respectively. The declarations use generic rest parameters (see #24897) to capture and reflect parameter lists in a strongly typed manner. InstrictBindCallApply mode these declarations are used in place of the (very permissive) declarations provided by typeFunction.
Caveats
Since the stricter checks may uncover previously unreported errors, this is a breaking change instrict mode.
Additionally,another caveat of this new functionality is that due to certain limitations,bind,call, andapply can’t yet fully model generic functions or functions that have overloads.When using these methods on a generic function, type parameters will be substituted with the empty object type ({}), and when used on a function with overloads, only the last overload will ever be modeled.
Generic spread expressions in object literals
In TypeScript 3.2, object literals now allow generic spread expressions which now produce intersection types, similar to theObject.assign function and JSX literals. For example:
tsfunctiontaggedObject<T,Uextendsstring>(obj:T,tag:U) {return { ...obj,tag };// T & { tag: U }}letx =taggedObject({x:10,y:20 },"point");// { x: number, y: number } & { tag: "point" }
Property assignments and non-generic spread expressions are merged to the greatest extent possible on either side of a generic spread expression. For example:
tsfunctionfoo1<T>(t:T,obj1: {a:string },obj2: {b:string }) {return { ...obj1,x:1, ...t, ...obj2,y:2 };// { a: string, x: number } & T & { b: string, y: number }}
Non-generic spread expressions continue to be processed as before: Call and construct signatures are stripped, only non-method properties are preserved, and for properties with the same name, the type of the rightmost property is used. This contrasts with intersection types which concatenate call and construct signatures, preserve all properties, and intersect the types of properties with the same name. Thus, spreads of the same types may produce different results when they are created through instantiation of generic types:
tsfunctionspread<T,U>(t:T,u:U) {return { ...t, ...u };// T & U}declareletx: {a:string;b:number };declarelety: {b:string;c:boolean };lets1 = { ...x, ...y };// { a: string, b: string, c: boolean }lets2 =spread(x,y);// { a: string, b: number } & { b: string, c: boolean }letb1 =s1.b;// stringletb2 =s2.b;// number & string
Generic object rest variables and parameters
TypeScript 3.2 also allows destructuring a rest binding from a generic variable. This is achieved by using the predefinedPick andExclude helper types fromlib.d.ts, and using the generic type in question as well as the names of the other bindings in the destructuring pattern.
tsfunctionexcludeTag<Textends {tag:string }>(obj:T) {let {tag, ...rest } =obj;returnrest;// Pick<T, Exclude<keyof T, "tag">>}consttaggedPoint = {x:10,y:20,tag:"point" };constpoint =excludeTag(taggedPoint);// { x: number, y: number }
BigInt
BigInts are part of an upcoming proposal in ECMAScript that allow us to model theoretically arbitrarily large integers.TypeScript 3.2 brings type-checking for BigInts, as well as support for emitting BigInt literals when targetingesnext.
BigInt support in TypeScript introduces a new primitive type called thebigint (all lowercase).You can get abigint by calling theBigInt() function or by writing out a BigInt literal by adding ann to the end of any integer numeric literal:
tsletfoo:bigint =BigInt(100);// the BigInt functionletbar:bigint =100n;// a BigInt literal// *Slaps roof of fibonacci function*// This bad boy returns ints that can get *so* big!functionfibonacci(n:bigint) {letresult =1n;for (letlast =0n,i =0n;i <n;i++) {constcurrent =result;result +=last;last =current;}returnresult;}fibonacci(10000n);
While you might imagine close interaction betweennumber andbigint, the two are separate domains.
tsdeclareletfoo:number;declareletbar:bigint;foo =bar;// error: Type 'bigint' is not assignable to type 'number'.bar =foo;// error: Type 'number' is not assignable to type 'bigint'.
As specified in ECMAScript, mixingnumbers andbigints in arithmetic operations is an error.You’ll have to explicitly convert values toBigInts.
tsconsole.log(3.141592 *10000n);// errorconsole.log(3145 *10n);// errorconsole.log(BigInt(3145) *10n);// okay!
Also important to note is thatbigints produce a new string when using thetypeof operator: the string"bigint".Thus, TypeScript correctly narrows usingtypeof as you’d expect.
tsfunctionwhatKindOfNumberIsIt(x:number |bigint) {if (typeofx ==="bigint") {console.log("'x' is a bigint!");}else {console.log("'x' is a floating-point number");}}
We’d like to extend a huge thanks toCaleb Sander for all the work on this feature.We’re grateful for the contribution, and we’re sure our users are too!
Caveats
As we mentioned, BigInt support is only available for theesnext target.It may not be obvious, but because BigInts have different behavior for mathematical operators like+,-,*, etc., providing functionality for older targets where the feature doesn’t exist (likees2017 and below) would involve rewriting each of these operations.TypeScript would need to dispatch to the correct behavior depending on the type, and so every addition, string concatenation, multiplication, etc. would involve a function call.
For that reason, we have no immediate plans to provide downleveling support.On the bright side, Node 11 and newer versions of Chrome already support this feature, so you’ll be able to use BigInts there when targetingesnext.
Certain targets may include a polyfill or BigInt-like runtime object.For those purposes you may want to addesnext.bigint to thelib setting in your compiler options.
Non-unit types as union discriminants
TypeScript 3.2 makes narrowing easier by relaxing rules for what it considers a discriminant property.Common properties of unions are now considered discriminants as long as they containsome singleton type (e.g. a string literal,null, orundefined), and they contain no generics.
As a result, TypeScript 3.2 considers theerror property in the following example to be a discriminant, whereas before it wouldn’t sinceError isn’t a singleton type.Thanks to this, narrowing works correctly in the body of theunwrap function.
tstypeResult<T> = {error:Error;data:null } | {error:null;data:T };functionunwrap<T>(result:Result<T>) {if (result.error) {// Here 'error' is non-nullthrowresult.error;}// Now 'data' is non-nullreturnresult.data;}
tsconfig.json inheritance via Node.js packages
TypeScript 3.2 now resolvestsconfig.jsons fromnode_modules. When using a bare path for theextends field intsconfig.json, TypeScript will dive intonode_modules packages for us.
{"":"@my-team/tsconfig-base","": ["./**/*"],"": {// Override certain options on a project-by-project basis."":false}}
Here, TypeScript will climb upnode_modules folders looking for a@my-team/tsconfig-base package. For each of those packages, TypeScript will first check whetherpackage.json contains a"tsconfig" field, and if it does, TypeScript will try to load a configuration file from that field. If neither exists, TypeScript will try to read from atsconfig.json at the root. This is similar to the lookup process for.js files in packages that Node uses, and the.d.ts lookup process that TypeScript already uses.
This feature can be extremely useful for bigger organizations, or projects with lots of distributed dependencies.
The new--showConfig flag
tsc, the TypeScript compiler, supports a new flag called--showConfig.When runningtsc --showConfig, TypeScript will calculate the effectivetsconfig.json (after calculating options inherited from theextends field) and print that out.This can be useful for diagnosing configuration issues in general.
Object.defineProperty declarations in JavaScript
When writing in JavaScript files (usingallowJs), TypeScript now recognizes declarations that useObject.defineProperty.This means you’ll get better completions, and stronger type-checking when enabling type-checking in JavaScript files (by turning on thecheckJs option or adding a// @ts-check comment to the top of your file).
js// @ts-checkletobj = {};Object.defineProperty(obj,"x", {value:"hello",writable:false });obj.x.toLowercase();// ~~~~~~~~~~~// error:// Property 'toLowercase' does not exist on type 'string'.// Did you mean 'toLowerCase'?obj.x ="world";// ~// error:// Cannot assign to 'x' because it is a read-only property.
The TypeScript docs are an open source project. Help us improve these pagesby sending a Pull Request ❤
Last updated: Nov 25, 2025