So What’s New in Typescript 3.2?
A quick overview of the newest release of Microsoft's typescript version 3.2 and all the news about changes and stricter types.

Typescript is an open-source, strongly-typed, object-oriented compiled language developed and maintained by Microsoft. It is basically JavaScript on steroids (it is a super-set of javascript) with static typing options.
It is designed for the development of large and scalable applications that compiles to JavaScript. A few days ago, the team at Microsoft released the latest version of Typescript and we are going to take a look at the new stuff 🎊
Tip: Build faster by sharing components as a team. Try Bit (open-source) to share, discover and use your components across projects and apps. It’s free.
strictBindCallApply
Earlier versions of typescript could not model the bind, call and apply methods on functions that would let binding this be possible and partially applying arguments on them and even call functions with different values for this to calling functions with an array for their arguments.
From the parameter types of version 2 the team started bringing these modeling capabilities to life, then tuple types came in version 3 opening up the ways to correctly type bind call and apply without hard-coding the whole logic. So TypeScript 3.2 ships with a new --strictBindCallApply
compiler option with which the bind
, call
, and apply
methods on function objects are strongly typed and strictly checked.
function foo(a: number, b: string): string {
return a + b;
}let a = foo.apply(undefined, [10]); // error: too few arguments
let b = foo.apply(undefined, [10, 20]); // error: 2nd argument is a number
let c = foo.apply(undefined, [10, "hello", 30]); // error: too many arguments
let d = foo.apply(undefined, [10, "hello"]); // okay! returns a string
So here two new types are brought into the lib.d.ts file, callableFunction and NewablwFunction; they contain specialized methods declarations for the bind, call and apply for both the regular functions and constructor functions.
Generic spread expressions in object literals
If you are a javascript developer, you might have heard about spreads, a good way to copy existing properties from an object into a new object. This is done by defining an element with three periods “…” , as a super-set of javascript, typescript handles this easily anywhere it has sufficient information about the type but it would not work with generics at all. Now in TypeScript 3.2, generic spread expressions are now allowed by object literals which now produce intersection types, similar to the Object.assign
function and JSX literals. For example:
function taggedObject<T, U extends string>(obj: T, tag: U) {
return { ...obj, tag }; // T & { tag: U }
}let x = 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:
function foo1<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 }
}
For non-generic spread expressions, Call and construct signatures have been stripped off, non-method properties are kept and properties with the same name gets the property of the rightmost property (if that makes any sense). Intersection types, however, concatenates call and construct signatures, all properties are kept and types of properties with the same name are intersected. This would clearly produce a variety of spreads for properties with the same name.
function spread<T, U>(t: T, u: U) {
return { ...t, ...u }; // T & U
}declare let x: { a: string, b: number };
declare let y: { b: string, c: boolean };let s1 = { ...x, ...y }; // { a: string, b: string, c: boolean }
let s2 = spread(x, y); // { a: string, b: number } & { b: string, c: boolean }
let b1 = s1.b; // string
let b2 = s2.b; // number & string
Generic object rest variables and parameters
In this new version of typescript, you can de-structure a rest binding from a generic variable. Just use the predefined pick and exclude helper types in the lib.d.ts, also use the generic type as well s the names of the other bindings.
function excludeTag<T extends { tag: string }>(obj: T) {
let { tag, ...rest } = obj;
return rest; // Pick<T, Exclude<keyof T, "tag">>
}const taggedPoint = { x: 10, y: 20, tag: "point" };
const point = excludeTag(taggedPoint); // { x: number, y: number }
BigInt
BigInts are a part of an upcoming ECMAScript proposal that allow modeling theoretically arbitrarily large integers. TypeScript 3.2 ships with type-checking for BigInts along with support for emitting BigInt literals when targeting esnext. So we have a new type called bigint, just call BigInt() or write BigInt literal by adding n to the end of any integer numeric literal.
let foo: bigint = BigInt(100); // the BigInt function
let bar: bigint = 100n; // a BigInt literal// *Slaps roof of fibonacci function*
// This bad boy returns ints that can get *so* big!
function fibonacci(n: bigint) {
let result = 1n;
for (let last = 0n, i = 0n; i < n; i++) {
const current = result;
result += last;
last = current;
}
return result;
}fibonacci(10000n)
While you might imagine close interaction between number
and bigint
, the two are separate domains.
declare let foo: number;
declare let bar: 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, mixing numbers and bigint in arithmetic operations is an error. You’ll have to explicitly convert values to BigInt
console.log(3.141592 * 10000n); // error
console.log(3145 * 10n); // error
console.log(BigInt(3145) * 10n); // okay!
Additionally, note is that bigint
produces a new string when using the typeof
operator: the string "bigint"
. TypeScript correctly narrows using typeof
as expected.
function whatKindOfNumberIsIt(x: number | bigint) {
if (typeof x === "bigint") {
console.log("'x' is a bigint!");
}
else {
console.log("'x' is a floating-point number");
}
}
Non-unit types as union discriminants
Narrowing is now easier to achieve in this new version of typescript, so the rules it considers for a discriminant property has been relaxed. Common properties of unions are now deemed discriminants as long as they contain some singleton type say a string literal, null
, or undefined
and they contain no generics. TypeScript 3.2 considers the error
property in the following example to be a discriminant, this was not so in previous versions since Error
isn’t a singleton type. With this, narrowing works correctly in the body of the unwrap
function.
type Result<T> =
| { error: Error; data: null }
| { error: null; data: T };function unwrap<T>(result: Result<T>) {
if (result.error) {
// Here 'error' is non-null
throw result.error;
} // Now 'data' is non-null
return result.data;
}
tsconfig.json
inheritance
TypeScript has supported extending tsconfig.json files by using the extends field for a while now. This just eases ambiguity and avoids duplication of configuration, every project just has a common tsconfig.json file. Some projects, however, are published as full independent packages so ther isn’t a common tsconfig.json they can reference, developers work around it by creating separate packages and referencing the separate file.
TypeScript 3.2 now resolves tsconfig.json
s from node_modules
. When using a bare path for the "extends"
field in tsconfig.json
, TypeScript will dive into node_modules
packages for us.
{
"extends": "@my-team/tsconfig-base",
"include": ["./**/*"]
"compilerOptions": {
// Override certain options on a project-by-project basis.
"strictBindCallApply": false,
}
}
Here, TypeScript traverses the node_modules
folders looking for any @my-team/tsconfig-base
package. For each of those packages found, it will first check if thepackage.json
has a "tsconfig"
field, and if it does, it will try to load a configuration file from that field. If none exists, it will try to read from a tsconfig.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.
The new --showConfig
flag
The TypeScript compiler, tsc in this new version now supports a new flag called –showConfig. If you run
tsc –-showConfig
TypeScript will calculate the effective tsconfig.json and print it out, which can be really useful for diagnosing configuration issues in general.
Object.defineProperty
declarations
When writing in JavaScript files using allowJs, the new TypeScript 3.2 recognizes declarations that use Object.defineProperty. This means we get better completions, and stronger type-checking when enabling type-checking in JavaScript files.
// @ts-checklet obj = {};
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.
Do you know Create-React-App now supports typescript in her newest version? Now you do 😃
Error Messages get a Makeover
If you use typescript, you are witness to the fact that there is serious thought that goes into the whole error and error reporting and documentation experience. This new version still goes deeper into this with the following new stuff:
- Better missing property errors (and cleaner missing attributes in JSX)
- Better error spans in arrays and arrow functions
- Error on most-overlapping types in unions (a.k.a. “pick most overlappy type”)
- Related spans when a typed
this
is shadowed - “Did you forget a semicolon?” on parenthesized expressions on the next line
- More specific messages when assigning to
const
/readonly
bindings - More accurate message when extending complex types
- Use relative module names in error messagesBreaking changes and deprecations
lib.d.ts
changes
TypeScript has recently moved more to generating DOM declarations in lib.d.ts
by leveraging IDL files provided by standards groups. Upgraders should note take note of any issues they encounter related to the DOM and report them.
More specific types
Certain parameters no longer accept null
, or now accept more specific types as per the corresponding specifications that describe the DOM.
More platform-specific deprecations
Certain properties that are WebKit-specific have been deprecated. They are likely to be removed in a new version.
wheelDelta
and friends have been removed.
wheelDeltaX
, wheelDelta
, and wheelDeltaZ
have all been removed as they are deprecated properties on WheelEvent
s.
As a solution, you can use deltaX
, deltaY
, and deltaZ
instead. If older runtimes are a concern, you can include a file called legacy.d.ts
in your project and write the following in it:
// legacy.d.tsinterface WheelEvent {
readonly wheelDelta: number;
readonly wheelDeltaX: number;
readonly wheelDeltaZ: number;
}
JSX resolution changes
The logic used for resolving JSX invocations has been unified with the logic for resolving function calls. While this has simplified the compiler codebase and improved some use-cases, there may be some differences which we may need to reconcile. These changes are likely unintentional so they are not breaking changes, but upgraders should note take note of any issues they encounter and report them.
Important Need-to-Knows
Here we would look at some caveats that ships with some new changes in this new typescript version:
- The use of strictBindCallApply might uncover previously unreported errors so it is a a breaking change in the strict mode.
2. The strictBindCallApply cannot fully model functions with overloads, in any case, the last overload would be the only one modeled.
3. Bigint is only available for the esnext target
Installing Typescript
Easily install with this line of npm command:
npm install -g typescript
Conclusion
We have seen the new typescript release and according to the roadmap here the next release is in 2 months time so wait for it. Remember you get massive typescript support if you use VS Code (do you use VS Code?). What is your favorite new addition to typescript? Let me know in the comments.