Tips for successfully typing the backtick character when transitioning to Typescript:

I am currently working on a Typescript Vue project involving Leaflet. I came across some code for lazy-loading map markers, but it was written in Javascript. Although the code works fine, I keep receiving errors and warnings from VSCode because this is not properly typed. How can I add type annotations to this?

Update 1: With @aplet123's suggestion, I managed to resolve the first type issue. However, I am stuck with the second one related to this._updateIconVisibility. It seems that this problem arises because I am extending existing functionality (i.e., _updateIconVisibility does not actually exist as a type). What should be my next step? I assume it might be best practice to create a custom class with the necessary methods, but I am unsure if using an anonymous object or another approach is more common...

L.Marker.addInitHook(function (this: L.Marker) {
    this.on(
        'add',
        function () {
            this._updateIconVisibility = function () {
                var map = this._map,
                    isVisible = map.getBounds().contains(this.getLatLng()),
                    wasVisible = this._wasVisible,
                    icon = this._icon,
                    iconParent = this._iconParent,
                    shadow = this._shadow,
                    shadowParent = this._shadowParent

                // remember parent of icon
                if (!iconParent) {
                    iconParent = this._iconParent = icon.parentNode
                }
                if (shadow && !shadowParent) {
                    shadowParent = this._shadowParent = shadow.parentNode
                }

                // add/remove from DOM on change
                if (isVisible != wasVisible) {
                    if (isVisible) {
                        iconParent.appendChild(icon)
                        if (shadow) {
                            shadowParent.appendChild(shadow)
                        }
                    } else {
                        iconParent.removeChild(icon)
                        if (shadow) {
                            shadowParent.removeChild(shadow)
                        }
                    }

                    this._wasVisible = isVisible
                }
            }

            // on map size change, remove/add icon from/to DOM
            this._map.on(
                'resize moveend zoomend',
                this._updateIconVisibility,
                this
            )
            this._updateIconVisibility()
        },
        this
    )
})

https://i.sstatic.net/0edzh.png

Answer №1

I have put together a solution for your code that addresses the errors and provides guidance on moving forward. While I may not be well-versed in your environment (Vue, etc.), this file serves as scaffolding to help you understand the process.

The key lies in accurately defining your this types at each stage. By creating a structure, implementing a type called MyObject, and specifying this as type MyObject where necessary, we can resolve the issues.

Please review the modified code below and feel free to ask if there are any unclear areas.

//  Additional setup to accommodate environmental requirements
namespace L {
    type handler = () => void

    type target = object;

    export type on = (types: string, handler: handler, target: target) => void

    export interface Marker {
        on: on
    }
}

const L = {
    Marker: {
        addInitHook: function(f: (this: L.Marker) => void) {
            //  Placeholder instruction based on code input
        }
    }
}

//  Introduced type for integration into your code
namespace L {
    export type MyObject = {
        _updateIconVisibility: () => void,
        _map: {
            on: on
        }
    }
}

//  Your existing code with TypeScript compiler compliance
L.Marker.addInitHook(function (this: L.Marker) {
    this.on(
        'add',
        function (this: L.MyObject) {
            this._updateIconVisibility = function () {
                var map = this._map,
                    isVisible = map.getBounds().contains(this.getLatLng()),
                    wasVisible = this._wasVisible,
                    icon = this._icon,
                    iconParent = this._iconParent,
                    shadow = this._shadow,
                    shadowParent = this._shadowParent

                // Retain parent of icon
                if (!iconParent) {
                    iconParent = this._iconParent = icon.parentNode
                }
                if (shadow && !shadowParent) {
                    shadowParent = this._shadowParent = shadow.parentNode
                }

                // Add/remove from DOM based on changes
                if (isVisible != wasVisible) {
                    if (isVisible) {
                        iconParent.appendChild(icon)
                        if (shadow) {
                            shadowParent.appendChild(shadow)
                        }
                    } else {
                        iconParent.removeChild(icon)
                        if (shadow) {
                            shadowParent.removeChild(shadow)
                        }
                    }

                    this._wasVisible = isVisible
                }
            }

            // Update visibility of icon in DOM upon map size change
            this._map.on(
                'resize moveend zoomend',
                this._updateIconVisibility,
                this
            )
            this._updateIconVisibility()
        },
        this
    )
})

Answer №2

After listening to David's response, I decided to create an interface that includes elements for the enhanced functionality I needed. Here's how it turned out:

interface LazyMarker extends Marker {
    _wasVisible: boolean
    _icon: ((Node & ParentNode) | null) & Icon
    _iconParent: (Node & ParentNode) | null
    _shadowParent: (Node & ParentNode) | null
    _updateIconVisibility(): void
}

// By using this hook, the markers can lazy load which ultimately boosts the performance of map scrolling and moving.
L.Marker.addInitHook(function (this: LazyMarker) {
    this.on(
        'add',
        function (this: LazyMarker) {
            this._updateIconVisibility = function (this: LazyMarker) {
                var map = this._map,
                    isVisible = map.getBounds().contains(this.getLatLng()),
                    wasVisible = this._wasVisible,
                    icon = this._icon,
                    iconParent = this._iconParent,
                    shadow = this._shadow,
                    shadowParent = this._shadowParent

                // Storing the parent of the icon
                if (!iconParent) {
                    iconParent = this._iconParent = icon.parentNode
                }
                if (shadow && !shadowParent) {
                    shadowParent = this._shadowParent = shadow.parentNode
                }

                // Adding/removing from DOM based on changes
                if (iconParent != null && isVisible != wasVisible) {
                    if (isVisible) {
                        iconParent.appendChild(icon)
                        if (shadowParent != null && shadow) {
                            shadowParent.appendChild(shadow)
                        }
                    } else {
                        iconParent.removeChild(icon)
                        if (shadowParent != null && shadow) {
                            shadowParent.removeChild(shadow)
                        }
                    }

                    this._wasVisible = isVisible
                }
            }

            // On map size change, remove/add icon from/to DOM
            this._map.on(
                'resize moveend zoomend',
                this._updateIconVisibility,
                this
            )
            this._updateIconVisibility()
        },
        this
    )
})

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

Creating a numeric sequence based on the date of a corresponding transaction - a step-by-step guide

INTRO I built an e-commerce app with TypeScript and Sequelize ORM. In the app, I have a table that generates sequential invoice numbers based on the current day. CREATE TABLE `dm_generate_trx` ( `id` int NOT NULL AUTO_INCREMENT, `date` date NOT NULL, ...

Handling HTTP errors in Angular when receiving a JSON response

I'm struggling to resolve this issue and I've searched online with no luck. The problem lies in my post call implementation, which looks like this: return this.http.post(url, body, { headers: ConnectFunctions.getHeader() }).pipe( map(result =&g ...

Directly invoking the child component results in null values being retrieved from Vuex

Utilizing VueJS with webpack, vuex, and vue-router has been quite the journey. I've encountered an issue while trying to determine whether a user is registered or not using the computed functionality in a child component. The computed function attempt ...

What is the best way to transition this endpoint from JavaScript to TypeScript?

I'm in the process of building a chat application with the t3 stack. I've successfully created a socket endpoint using JavaScript, but now I'm facing some challenges as I try to convert it to TypeScript. import { Server } from "Socket.I ...

Testbed: Issue encountered: Unable to resolve all parameters for PriDateInput component

I am facing an issue while creating an Angular Component with the help of TestBed. The error message I receive is as follows: Error: Can't resolve all parameters for PriDateInput: (?). error properties: Object({ ngSyntaxError: true }) ...

Using both withNextIntl and withPlaiceholder simultaneously in a NextJS project causes compatibility issues

I recently upgraded to NextJS 14 and encountered an issue when deploying my project on Vercel. The next.config.mjs file in which I wrapped my nextConfig in two plugins seemed to prevent the build from completing successfully. As a workaround, I decided t ...

Strategies for resolving a mix of different data types within a single parameter

Here, I am setting up the options params to accept a value that can either be a single string or another object like options?: string[] | IServiceDetail[] | IServiceAccordion[]; However, when attempting to map these objects, an error is encountered: Prope ...

Hand over the component method as an argument to a class

One of my components, called First, is responsible for creating a new instance of a Worker class. During the creation process of this class, I intend to pass the Read method as a callback method. Once this class completes its task, it will then invoke thi ...

Tips for integrating an arrow function as a property in a functional programming approach using JavaScript or TypeScript

Suppose I were to create a constructor for a functional class with TypeA as an argument, and TypeB representing the type of the class itself. In such cases, I can implement it using: functionName(argument: TypeA): TypeB { this.property = argument; ...

Encountering an issue while attempting to initiate a nested array: "Cannot assign a value to an optional property access in the left-hand side of an assignment expression."

I am dealing with an object that contains nested arrays, structured like this: export class OrdenCompra { public id?: number, public insumos?: OrdenCompraInsumo[], } export class OrdenCompraInsumo { id?: number; traslados?: IImpuestoTraslado[]; } export ...

The type definition file for 'bson' could not be located. It appears to be missing from the program due to being the entry point for the implicit type library 'bson'

I recently set up a new Typescript/React project and encountered the following error in the tsconfig.json file: "Cannot find type definition file for 'bson'. The file is in the program because: Entry point for implicit type library 'bson&ap ...

Updating a boolean value when the checkbox is selected

Hey there! I'm currently working on a project using Angular and have a collection of elements that can be checked, which you can check out here. In terms of my business logic: stateChange(event: any, illRecipe: Attendance){ var state: State = { ...

What is the best way to refresh a computed property in a Vue component?

Here's an example of my Vue component structure: <template> <div> <ul class="list-inline list-photo"> <li v-for="item in items"> <template v-if="photoList[item]"> ...

Ionic Vue is throwing an error indicating that a property is not found on the type '{ $route(currentRoute: any): void; }'

Currently, I am developing an Ionic WebApp using Vue and TypeScript. My current task involves retrieving the current id parsed by the route. To achieve this, I have been working on a watcher: export default { data() { return { ...

Encountering an error when attempting to add the 'shelljs' module to an Angular 2 TypeScript project

I am facing an issue with including the shelljs library in my Angular 2 TypeScript project. I have already added the shelljs.d.ts file to the node_modules/shelljs directory. Below is my package.json configuration: "name": "myproj1", "description": "myp ...

Guidance on specifying a type based on an enum in Javascript

I have a list of animals in an enum that I want to use to declare specific types. For instance: enum Animals { CAT = 'cat', DOG = 'dog', } Based on this Animal enum, I wish to declare a type structure like so: type AnimalType = { ...

Unable to determine all parameters for Modal: (?, ?, ?)

import { Component, Inject } from '@angular/core'; import { NavController, Modal } from 'ionic-angular'; import { PopupPage } from '../../components/modal/modal.page'; @Component({ templateUrl: 'build/pages/spot/spot. ...

Leveraging the combination of Express JS and Vue.js within the Electron framework

Can you combine Vue.js and Express JS in a project with Electron JS? How would this work? I currently have a project running on Vue.js and Electron JS, but I'm unsure how to integrate Express JS into it. Any guidance would be greatly appreciated. ...

You can't observe the behavior of simulated functions in a class with a manually created mock

Kindly note that I have set up a comprehensive Github repository where you can download and explore the content yourself here I am currently working on mocking a non-default exported class within a module using a manual mock placed in the folder __mocks__ ...

What could be the reason behind receiving a "Failed to load resource" error when attempting to mount a component in Vue.js?

I am facing two errors in my Vue components related to mounting the component. The console log is showing 404 errors as follows: 1) [Error] Failed to load resource: the server responded with a status of 404 (Not Found) localhot8000/movies/getComments 2) [ ...