Change a nullable string property within an interface to a non-nullable string property

Looking at two interfaces, one with a nullable vin and the other without:

interface IVehicle {
    vin: string | null;
    model: string;
}

interface IVehicleNonNullVin {
    vin: string;
    model: string;
}

The goal is to convert a model from IVehicle to IVehicleNonNullVin when it's confirmed that vin is not null.

Take this scenario for example:

const myVehicle: IVehicle = {
    vin: 'abc123',
    model: 'm3'
};

const needsVin = (_: IVehicleNonNullVin) => false;

if (myVehicle.vin === null) {
    throw new Error('null');
} else {
    needsVin(myVehicle);
 // ~~~~~~~~~~~~~~~~~~~ 'IVehicle' is not assignable to 'IVehicleNonNullVin'
}

This results in the following error message:

Argument of type 'IVehicle' is not assignable to parameter of type 'IVehicleNonNullVin'.
Types of property 'vin' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.

Even though it's certain that the property is not nullable in this case.

Q: How can TypeScript be convinced that the existing model conforms to the type based on type checks within the code flow?

Demo in TS Playground


Workarounds

One workaround involves casting the type (although it disregards the existing type safety):

needsVin(myVehicle as IVehicleNonNullVin);

Alternatively, creating a new model is an option (but may not be ideal for large numbers of properties):

const nonNullVehicle: IVehicleNonNullVin = {
    model: myVehicle.model,
    vin: myVehicle.vin
}
needsVin(nonNullVehicle);

Answer №1

You can create a custom type predicate to establish a user-defined type guard like so:

const isNotEmptyVin = (vehicle: IVehicle): vehicle is IVehicleNonNullVin =>{
    return vehicle.vin !== null
}

if (!isNotEmptyVin(myVehicle)) {
    throw new Error('vin cannot be null');
} else {
    processVin(myVehicle);
}

TypeScript will narrow down the variable to that specific type if it aligns with the original type.

Try Demo in TS Fiddle

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

The generics in TypeScript for Parameters<URLS[T]> and the corresponding URLS[T] are not compatible

In the code below, I am encountering a type error: const urls = { inviteNewUser: ({teamId, intent = 'invite'}: {teamId: string; intent?: Intent}) => `/magic-link?intent=${intent}&teamId=${teamId}`, resetPassword: ({intent = 'r ...

React animation failing to render underline animation

After tinkering with the underline animation while scrolling down on Codepen using Javascript, I successfully implemented it. You can check out the working version on Codepen. This animation utilizes Intersection Observer and a generated svg for the underl ...

Add a class individually for each element when the mouse enters the event

How can I apply the (.fill) class to each child element when hovering over them individually? I tried writing this code in TypeScript and added a mouseenter event, but upon opening the file, the .fill class is already applied to all elements. Why is this ...

ESLint version 8.0.0 encountered an error while attempting to fetch the '@typescript-eslint' plugin

Hey there, I'm in need of some assistance. I encountered an error while trying to build a project. Uh-oh! Something didn't go as planned! :( ESLint: 8.0.0 TypeError: Failed to load plugin '@typescript-eslint' specified in ' ...

Difficulty in connecting React to Node.js with the use of axios

Recently, I embarked on a project using React and Node to create an app that allows users to add people data to a database. The frontend is built with React and can be accessed at localhost:3000, while the backend, developed with Node, runs on localhost:33 ...

Convert JSON data into an array of strings that are related to each other

I'm encountering an issue with converting JSON into a string array I must convert a JSON into a string array to dynamically INSERT it into our database, as I need this to work for any type of JSON without prior knowledge of its structure. Here is th ...

Filter the output from a function that has the ability to produce a Promise returning a boolean value or a

I can't help but wonder if anyone has encountered this issue before. Prior to this, my EventHandler structure looked like: export interface EventHandler { name: string; canHandleEvent(event: EventEntity): boolean; handleEvent(event: EventEntity ...

Potential absence of the object has been detected after performing object verification

I encountered an issue with the following error message: Object is possibly 'undefined'.ts(2532) This is what my configuration looks like: export interface IDataColumns { name: string; label: string; display: string; empty: boolean; fi ...

Discovering the current page using ons-navigator in Onsen UI

I am currently attempting to determine the page I am on while using the popPage() function with Onsen UI's ons-navigator. I have tried the following methods, but they always return false regardless: this.navigator.nativeElement.popPage().then((page: a ...

Tips for integrating TypeScript with Vue.js and Single File Components

After extensive searching online, I have struggled to find a straightforward and up-to-date example of setting up Vue.js with TypeScript. The typical tutorials out there either are outdated or rely on specific configurations that don't apply universal ...

In TypeScript, is it possible to indicate that a function will explicitly define a variable?

In TypeScript, I am working on creating a class that delays the computation of its information until it is first requested, and then caches it for future use. The basic logic can be summarized as follows. let foo: string | undefined = undefined; function d ...

Retrieving information from a JSON API using Angular with Typescript

Currently, I am dealing with an API JSON to fetch a list of countries, followed by a list of states, and then cities within that state and country. The challenge lies in the second API call that I make. In the beginning, I load a list of continents and the ...

A guide to building a versatile higher-order function using TypeScript

I'm struggling with creating a function that can add functionality to another function in a generic way. Here's my current approach: /** * Creates a function that first calls originalFunction, followed by newFunction. * The created function re ...

Loading an index.html file using Webpack 3, Typescript, and the file-loader: A step-by-step guide

Attempting to utilize the file-loader and Webpack 3 to load my index.html file is proving to be a challenge. The configuration in my webpack.config.ts file appears as follows: import * as webpack from 'webpack'; const config: webpack.Configura ...

Clicking on the React Bootstrap Checkbox within the Nav component does not trigger a rerender of the NavItem component

Encountering an unusual issue while using a Nav and NavItem with a Checkbox from React Bootstrap. What I've noticed is that when clicking directly on the checkbox instead of the NavItem button, the checkbox does not re-render correctly even though my ...

Some files are missing when performing an npm install for a local package

My project is structured like this: ├── functions/ │ ├── src │ ├── lib │ ├── package.json ├── shared/ │ ├── src │ | ├── index.ts | | ├── interfaces.ts | | └── validator_cl ...

Use a pipe to show the content of the md-input

In my Angular 2 Material application, I have a form that includes a price input: <md-input [(ngModel)]="price" placeholder="Price"> </md-input>{{price|customCurrency}} This input field uses a custom version of the CurrencyPipe which you c ...

Customizing the output format of Ng Date Picker beyond the standard ISO-8601

Just to clarify, I'm talking about a specific DatePicker component that can be found at the following link: Although the DatePicker interface is user-friendly and visually appealing, I'm facing an issue with the way it outputs values. While ther ...

Is it possible to execute TestCafe tests using TypeScript page objects that have not been utilized?

While working with TestCafe, I am implementing tests using the Page Objects pattern. I have already written some page objects in advance, even before their actual usage, as I am familiar with the page and know what to anticipate. However, when attempting ...

Preventing memory leaks in unmounted components: A guide

Currently, I am facing an issue while fetching and inserting data using axios in my useState hook. The fetched data needs to be stored as an array, but unfortunately, I encountered a memory leak error. I have tried various solutions including using clean u ...