Ways to specify DOM as potentially being undefined

My team and I are currently in the process of building a new Vue SSR application using Nuxt within a monorepo setup. We have organized the Nuxt app as a package, with another package serving as our component library. While we are relatively new to Typescript, we managed to set up everything smoothly.

However, we encountered an issue: the component library needs to be SSR-friendly but should not have dependencies on Nuxt itself. In order to access window properties, I prefer using

if (typeof window !== 'undefined')
over if (process.browser). This leads me to wonder if it is possible to utilize Typescript and Eslint to generate an error when someone attempts to access window properties without verifying if they are defined first.

// Not SSR friendly
const halfWinHeight = window.innerHeight / 2

// SSR friendly
if (typeof window !== 'undefined') {
  const halfWinHeight = window.innerHeight / 2
}

I am aware that Typescript will throw an error if a union type like the following is utilized:

declare const window: {} | undefined

This would result in the desired error message Object is possibly 'undefined'.

https://i.sstatic.net/vSaLc.png

In essence, my goal is to avoid specifying all potential window and document properties individually. Instead, I am exploring the option of utilizing a lib such as DOM, but one that could potentially be undefined. The challenge lies in the fact that we only ascertain whether window is defined or not during runtime, so how can I provide it with a value to inform Typescript at compile time?

I am attempting to tackle this issue with Typescript, although there may be alternative approaches to consider. Any assistance on this matter would be immensely appreciated.

Answer №1

Here is a potential solution:

  1. Utilize the dom library to acquire the type declarations for window:

    // tsconfig.json
    {
      "compilerOptions": {
        "lib": ["dom"]
      }
    }
    
  2. Develop a utility file that exports window, specifying it as typeof window | undefined:

    // @/utils/window.ts
    export default window as typeof window | undefined
    
  3. In every file that references window (from dom), import the utility file as window to ensure that your custom typed version is used instead:

    // MyFoo.vue
    import window from '@/utils/window'
    
    export default {
      mounted() {
        window.console.log('hi')  // ❌ Object is possibly 'undefined'
        ^^^^^^
    
        window?.console.log('hi') // ✅
      }
    }
    

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

Strange behavior observed with Nuxt Js asyncData method returning values

Currently, I am engaged in a project using nuxt js/vue js. The project requires me to interact with multiple REST APIs. To accomplish this task, I am utilizing the asyncData() function provided by nuxt js to make the API calls within the page component. i ...

Can someone please provide guidance on how I can access the current view of a Kendo Scheduler when switching between views, such as day view or week

<kendo-scheduler [kendoSchedulerBinding]="events" [selectedDate]="selectedDate" [group]="group" [resources]="resources" style="height: 600px;" [workDayStart]="workDayStart" [workDayEnd] ...

Error: The module parsing process failed due to the presence of an octal literal in strict mode. To resolve this issue,

I'm currently attempting to incorporate the following regular expression into Angular6: const regexp = new RegExp('^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2])\\2))(? ...

Guidance on utilizing Vuetify's "Select" dropdown list in Nuxt.js and Vue.js

When using nuxt.js in my form with a Vuetify "Select" Dropdown list, the dropdown items are not showing. How can I fix this error? <v-col class="d-flex" cols="12" sm="6" > <v-select :items="items" v-mode ...

Typescript often fails to recognize that every code path within a function should return a value

Is it possible to inform TypeScript that all potential code paths in a function will return a value? In my scenario, I provide two numeric arrays as input, verify their monotonically increasing nature, and then retrieve a value based on specific condition ...

Type definition for Vuex store functionality

Working on creating a versatile type to provide typing hints for mutations in Vuex. After reading an inspiring article on Vuex + TypeScript, I decided to develop something more generic. Here is what I came up with: export type MutationType<S, P, K exten ...

Vite - Issue with Copying Static Files

I have a Vue.js application that makes use of Vite. Within this app, there are two static files - favicon.ico and manifest.json - that need to be copied to the dist directory. Below is how my vite.config.js file is set up: import { defineConfig } from &apo ...

In Vue, the concept of using the debounce method is not clearly defined

I am aware that using the arrow syntax for a method can cause 'this' to not be mapped to the Vue instance. In my case, I am utilizing lodash.debounce and I don't think I'm using the arrow syntax here? Encountering Error: Cannot read pr ...

How can I retrieve a certain type of object property in TypeScript?

Imagine having a collection of flags stored in an object like the example below: type Flags = { flag1: string, flag2: string, flag3: boolean, flag4: number } // const myFlags: Flags = { // flag1: 'value 1', // flag2: 'value 1&ap ...

How to send parameters through the Google Maps API URL using Vue.js

When using $router.push(), I receive two parameters: {{ this.$route.params.lat }} and {{ this.$route.params.lng }}, which are latitude and longitude coordinates. To access a Google Maps URL, I need to include both of these parameters: https://maps.googlea ...

Pinia seems to be failing to refresh and display the latest image

My store and state is updating correctly. I'm currently using Ionic along with vue.js composition using Pinia. After making a selection on a previous route to choose a new image, the image gets updated properly in pinia, but it does not reactively ch ...

Utilize tags as properties in Vue.js by selecting them

I am attempting to retrieve a value from a select tag and use it in an object property. Below is the HTML code: <div id="app"> <h3>{{title}}</h3> <div class="form"> <div class="form-group"> <div ...

Tips for successfully passing an image using props in Vuejs without experiencing the issue of disappearing content when there is no image present

Is there a way to make a component that can function with or without an image? Currently, when the component doesn't have an image, other contents and styles disappear. How can I resolve this issue? App.Vue: <template> <div id="app&qu ...

VueJS 3 custom Checkbox fails to update UI upon clicking

I'm attempting to implement a customized checkbox using Vue 3 and the composition API based on this example. However, despite confirming through devtools that all my props and bound data are successfully passed from the parent component to the child c ...

Loading local HTML files in Vue 3 (Vite) iframe consistently defaults to displaying index.html

I'm relatively new to Vue and I'm attempting to embed a local HTML file into my Vue template using an iframe. Despite encountering related questions and solutions, none have resolved my issue so far. Here is what my component currently looks lik ...

Chart rendering failure: unable to obtain context from the provided item

I am encountering an issue while trying to incorporate a chart from the charts.js library into my Vue.js and Vuetify application. The error message that keeps popping up is: Failed to create chart: can't acquire context from the given item Even af ...

Issue arises when fastify/websocket is being used and an argument of type '{ websocket: boolean; }' is not compatible or able to be assigned to a parameter

I am facing an issue with my new project that involves fastify and Typescript. The error I am encountering is as follows: Argument of type '{ websocket: boolean; }' is not assignable to parameter of type 'RouteShorthandOptions ...ts(2345) B ...

Alter the color scheme of the material dialog's background

I have been trying to change the background color of a dialog, but so far I have only been successful in changing the outline. I used the panelClass property as I believed it was the correct way to do it. https://stackblitz.com/edit/jm9gob ...

Unusual compilation issue encountered in Vue when trying to use a template for a slot

I encountered a strange issue where my Vue compiler was refusing to render the default named slot of a child component. Error: Codegen node is missing for element/if/for node. Apply appropriate transforms first. Even my VSCode highlighted this problem a ...

Can Nuxt accurately identify which page is accessing the /slug path?

In my project, I have a post page, a category page, and the usual internal pages all set up. Here's the current structure in the pages folder: pages/category/_id.vue - Sends request for a category pages/post/_id.vue - Sends request for a post pages/p ...