Is it possible for me to create a data type representing "potentially undefined strings"?

Just a heads up: I have enabled --strictNullChecks

Here is a function I have:

export function ensure<T, F extends T>(maybe: T | undefined, fallback: F): T {
  if (isDefined<T>(maybe)) {
    return maybe
  }

  if (fallback === undefined) {
    throw new Error('Could not ensure a value; please supply a fallback for the given variable')
  }

  return fallback
}

I typically use this function to remove the undefined part from a potentially undefined value.

const user = ensure(possiblyUndefinedUser, defaultUser)

My aim is for the below scenario,

const user = ensure(certainlyDefinedUser, defaultUser)

to trigger a compile time error. In other words, I want it to be against the rules to use this function with a value that the compiler already recognizes as having a value. This approach will compel me to accurately define types for my functions, as outlined below.

I've experimented with different variations of the generic arguments in an attempt to achieve a type like T | undefined that doesn't allow values of type T to be assigned to it. I understand that this may not be possible, but I thought I'd seek advice from the community instead of continuing to struggle on my own.


My objective here is: if I intend to pass an argument through a function like isNil or ensure, then I want to be compelled to update the argument type to be optional. If an argument is not optional, then I should be absolutely certain that there is no necessity to perform a null check on it.

Answer №1

To handle cases where the first parameter cannot be undefined, we can utilize conditional types to identify and trigger an error for the second parameter.

function isDefined<T>(v: T) : v is Exclude<T, undefined> {
    return !!v;
}

export function ensure<T, F extends (undefined extends T ? T : 'First param can\'t be undefined')>(maybe: T, fallback: F): Exclude<T, undefined> {
    if (isDefined<T>(maybe)) {
        return maybe
    }

    if (fallback === undefined) {
        throw new Error('Could not ensure a value; please supply a fallback for the given variable')
    }
    //A type assertion is needed here as F may not technically extend T
    return fallback as any;
}

declare var defaultUser: string|undefined;
declare var possiblyUndefinedUser: string| undefined
const user = ensure(possiblyUndefinedUser, defaultUser) //valid

declare var certainlyDefinedUser: string;
const user2 = ensure(certainlyDefinedUser, defaultUser); //encounter an error

Access the link to the TypeScript Playground where you must manually enable strict null checks.

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

Unexpected TypeError when using Response.send()

Here is a snippet of my simple express code: const api = Router() api.post('/some-point', async (req, res, next) => { const someStuffToSend = await Promise.resolve("hello"); res.json({ someStuffToSend }); }) In my development environmen ...

Vercel encountered issues with "validating code quality and type correctness" during deployment but was successful when performed locally

Running "next build" locally and "vercel build" both work smoothly. However, once deployed to vercel, the "Linting and checking validity of types" fails during the build process. It seems like TypeScript is stricter when building on vercel even with the sa ...

How can I ensure that all the text is always in lowercase in my Angular project?

Is there a way to ensure that when a user enters text into an input field to search for a chip, the text is always converted to lowercase before being processed? Currently, it seems possible for a user to create multiple chips with variations in capitaliza ...

Issue with interface result: does not match type

Hey there! I've been working on creating an interface in TypeScript to achieve the desired return as shown below: { "field": "departament_name", "errors": [ "constraint": "O nome do departam ...

The Angular Progressive Web App functions properly in ng serve mode, but encounters issues when running with http-server

I'm developing a Progressive Web App (PWA) using Angular. Everything was functioning smoothly until out of nowhere, I started encountering a 404 Error whenever I tried to navigate to a new component while serving in dist/project with http-server. Surp ...

Tips for troubleshooting 'npm ERR! 403: The requested package version is not permitted by your security policy. Typically, this issue arises when you or one of your dependencies are attempting to access a restricted package version.'

Currently, I am in the process of setting up a Jenkins and a private npm repository called Sonatype Nexus. I am encountering an error when attempting to publish to the repository within a Jenkins build pipeline. + npm publish --registry https://<my-priv ...

Issue with Angular standalone component importation causing rendering issue in HTML

Recently, I started working with Angular and I am currently creating a clone using Firebase. While working on this project, Angular is throwing two errors at me: The Component AppComponent is standalone and cannot be declared in an NgModule. Should it b ...

setting the minimum date for a datepicker

Does anyone know how to set the minimum date for a calendar to be 2 days from the current date? For example, if today is the 27th, the minimum date should be the 29th. Any suggestions? Thanks. https://i.sstatic.net/7yHhH.png #html code <mat-form-field ...

Testing the functionality of functions through unit testing with method decorators using mocha and sinon

I have a class method that looks like this: export class MyClass { @myDecorator() public async createItem(itemId: string, itemOptions: ItemOption[]): Promise<boolean> { // ... // return await create I ...

Clear out the existing elements in the array and replace them with fresh values

Within my Progressive Web App, I am utilizing HTTP requests to populate flip cards with responses. The content of the requests relies on the selected values. An issue arises when I choose an item from the dropdown menu. It triggers a request and displays ...

Combining switch statements from various classes

Is there a way to merge switch statements from two different classes, both with the same function name, into one without manually overriding the function or copying and pasting code? Class A: protected casesHandler(): void { switch (case){ ...

Avoid using <input oninput="this.value = this.value.toUpperCase()" /> as it should not convert the text displayed on the "UI", rather it should send the uppercase value

<input oninput="this.value = this.value.toUpperCase()" type="text" id="roleName" name="roleName" class="form-control width200px" [(ngModel)]="role.roleName"> Even though the UI is changing ...

Build an object using a deeply nested JSON structure

I am working with a JSON object received from my server in Angular and I want to create a custom object based on this data. { "showsHall": [ { "movies": [ "5b428ceb9d5b8e4228d14225", "5b428d229d5b8e4 ...

Looking to organize an array of objects containing two string elements (countries) based on the country name using TypeScript or the Lodash library?

Below is an example of an array of objects I am working with: { countries: [{ "country_alpha2_code": "PW", "country_name": "PALAU" },{ "country_alpha2_code": "US&qu ...

How is it possible that TypeScript does not provide a warning when a function is called with a different number of arguments than what is expected?

I am working on a vanilla JavaScript project in VS Code and have set up jsconfig.json. Here is an example of the code I am using: /** * @param {(arg: string) => void} nestedFunction */ function myFunction(nestedFunction) { // Some logic here } myFu ...

Having trouble initializing useReducer in React paired with TypeScript

I'm currently delving into the world of TypeScript and facing a challenge with setting up the useReducer function. It seems like the solution might be a simple one, so apologies in advance. Below is an excerpt from my App.tsx file: import React, { use ...

Having trouble getting the npm package with @emotion/react and vite to function properly

Encountering an issue with the npm package dependencies after publishing, specifically with @emotion/react. This problem arose while using vite for packaging. Upon installing the package in another project, the css property appears as css="[object Ob ...

Unexpected issue with Ionic 4 subarray returning as undefined even though the index is accurate

When attempting to use console.log to view the value, I noticed that the value of noticeSet2[index] is undefined. However, when I print noticeSet, all the data in the array is displayed. Additionally, after printing the index using console.log, it correctl ...

React-scripts is not recognizing tests that have the .tsx file extension

Currently in the process of converting my project to TypeScript, everything is almost working perfectly. The code builds without issues and renders correctly. The only hiccup I'm facing is with my tests. I've observed that when I change a test f ...

Transforming date and timezone offset into an isoDate format using moment.js

When retrieving data from the API, I encounter Date, Time, and Offset values in separate columns. My goal is to obtain an ISO date while maintaining the original date and time values. const date = "2019-04-15" const time = "13:45" const ...