How come a null variable continues to widen to type any even when strictNullChecks is enabled?

According to the TypeScript Documentation, if strictNullChecks is true, there should be no type widening. Also, the typeof nul should be null.

let nul = null; // typeof nul = any
let undef = undefined; // typeof undef = any

Check it out in the Playground

If you enable strictNullChecks in the TSConfig tab of the playground, you will see that the type of nul and undef is still "any". Why?

UPDATE:

Upon further investigation, I discovered something interesting thanks to @jcalz:

// strictNullChecks=true;
let z = null; // hover on z, quick info shows: let z: any <--
type A = typeof z; // type A = null

Play with it in the Playground

// strictNullChecks=false;
let z = null; // hover on z, quick info shows: let z: any 
type A = typeof z; // type A = any <---

Toggle off strictNullCheck in the Playground

Answer №1

The documentation you referenced was likely accurate at the time of TypeScript 2.0's release. However, with the rollout of TypeScript 2.1, there was an introduction of enhanced any inference, which was implemented in microsoft/TypeScript#11263.

Subsequently, enabling --noImplicitAny caused a change where uninitialized or initialized to null or undefined non-const variables would be inferred as type any rather than null or undefined, even when --strictNullChecks is activated. This applied to TypeScript code (as opposed to checking JavaScript files) as well:

let nLet = null; // any
let uLet = undefined; // any

var nVar = null; // any 
var uVar = undefined; // any 

const nConst = null; // null
const uConst = undefined;  // undefined 

The reasoning behind this seems to stem from the likelihood of modifying a variable initialized with null or undefined later on. The use of the any type enables control flow analysis for further narrowing:

let x = undefined;
while (!x) {
  if (Math.random() < 0.5) x = "finished";
}
x // string
x.toUpperCase(); // okay
x.toFixed(); // error 

This scenario exemplifies how the compiler permits assignment of a string to x within the loop and recognizes its type once outside the loop, facilitating treatment exclusively as a string.


Even during initial assignment, control flow analysis constrains the apparent type of these variables to null and

undefined</code, demonstrating a distinction from merely annotating a variable as type <code>any
:

let nLet = null; // any
nLet.x // error, Object is possibly 'null'

let uLet = undefined; // any
uLet.x // error, Object is possibly 'undefined' 

let aLet: any;
aLet.x // no error

In practical usage, minimal issues are expected when working with variables initialized to null or undefined.

Playground link showcasing the code

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

leveraging third party plugins to implement callbacks in TypeScript

When working with ajax calls in typical javascript, I have been using a specific pattern: myFunction() { var self = this; $.ajax({ // other options like url and stuff success: function () { self.someParsingFunction } } } In addition t ...

What is the method in TypeScript for defining a property in an interface based on the keys of another property that has an unknown structure?

I recently utilized a module that had the capability to perform a certain task function print(obj, key) { console.log(obj[key]) } print({'test': 'content'}, '/* vs code will show code recommendation when typing */') I am e ...

Enhancing Request JSON Body Validation in Next.js 14 API Handler

I'm currently in the process of developing an API for my iOS application using Next.js 14. I have managed to get it up and running successfully, however, I am facing some challenges when it comes to properly validating the body of a request. ESLint is ...

Exploring the implementation of method decorators that instantiate objects within Typescript

Currently, I have been working on a lambda project and utilizing the lambda-api package for development. As part of this process, I have implemented decorators named Get and Post to facilitate mapping routes within the lambda api object. These decorators e ...

Arrange the columns in Angular Material Table in various directions

Is there a way to sort all columns in an Angular material table by descending order, while keeping the active column sorted in ascending order? I have been trying to achieve this using the code below: @ViewChild(MatSort) sort: MatSort; <table matSort ...

Using Typescript to create a Checkbox Grid that displays pipe-delimited values and implements a custom validation rule

I am currently working with a checkbox grid that contains pairs of AccountIds (consisting of x number of digits) and file names separated by a pipe delimiter. The file names are structured to always begin with either PRC or FE followed by a varying combin ...

Ways to enhance a component by incorporating default properties in React/TypeScript

I am looking to enhance a React/TS component (specifically the @mui/x-data-grid DataGrid) by populating the classes prop with my own application classes. Initially, I thought about creating a new component called CustomDataGrid like this: import React fro ...

Is there a hashing algorithm that produces identical results in both Dart and TypeScript?

I am looking to create a unique identifier for my chat application. (Chat between my Flutter app and Angular web) Below is the code snippet written in Dart... String peerId = widget.peerid; //string ID value String currentUserId = widget.currentId ...

Angular is unable to access a service method through an observable subscription

Currently, I have a code for my service like this: cars() { return 'something here'; } Next, in order to retrieve the data using an observable from the component, I am attempting the following: getcars() { this.dataService.cars().subsc ...

I possess information stored within the array object below, and I aim to transform it into a different array object format

Here is the response I received from my API: let data = [ { date: '2021-04-27', formatted_date: 'Apr 27', location: [ { date: '2021-04-27', formatted_date: 'Apr 27', countr ...

angular2 fullCalendar height based on parent element

Currently, I am using angular2-fullcalendar and encountering an issue with setting the height to 'parent'. The parent element is a div but unfortunately, it does not work as expected. The navigation bar appears fine, however, the calendar itself ...

What is the process for upgrading TypeScript to the newest version using npm?

My current TypeScript version on my machine is 1.0.3.0 and I am looking to upgrade it to the latest version, which is 2.0. Could someone please guide me on how to accomplish this using npm? ...

What is the best way to pass a generic interface to the zustand create function in a TypeScript environment

Having trouble figuring out the right syntax to pass a generic interface when calling a function that accepts a generic type. My goal is to use: const data = itemStore<T>(state => state.data) import { create } from "zustand"; interface ...

Update ngModel value following the PUT request response

I currently have a variable named dummy_value and I would like to update it using an input box. <p>{{dummy_value}}</p> <input [(ngModel)]="dummy_value" /> Upon making this change, the dummy_value updates instantly due to the two-way bin ...

Exploring Child Types in Typescript and JSX minus the React framework

It seems like there's a missing piece of the puzzle that I can't quite figure out. Despite going through the documentation on JSX in non-React settings, I'm still unable to spot my mistake. Let's examine the following code: /** @jsx pra ...

Checking to see if a string meets the criteria of being a valid ARGB value

How do I verify that a string represents a valid ARGB value, such as #ffffffff for ARGB 255,255,255,255? Is there a way to validate this using TypeScript and C#? ...

In React Router v6, you can now include a custom parameter in createBrowserRouter

Hey there! I'm currently diving into react router v6 and struggling to add custom params in the route object. Unfortunately, I haven't been able to find any examples of how to do it. const AdminRoutes: FunctionComponent = () => { const ...

Angular: sending the user input to the component

I'm trying to link the value of an HTML input field to a variable 'numToAdd' in my component, and then increment the 'numToAdd' variable by 1. However, I'm facing difficulties passing the input value to the component variable. ...

Error: In Angular Firebase, the type 'string' cannot be assigned to the type 'Date'

I am encountering an error. The following error is shown: "cannot read property 'toDate' of undefined. Without the toDate() | Date." After further investigation, I found: A Timestamp object with seconds=1545109200 and nanoseconds=0. A hel ...

Methods cannot be called on TypeScript primitive strings

In my exploration of TypeScript, I came across the concept that the string primitive type does not have any methods and is simply a value. To utilize methods such as toLowerCase(), one must work with the String type instead. Curious about this distinction ...