Combining the Partial<CssStyleDeclaration> union type with a dictionary can lead to potential typing complications when the implicit any flag is

Using VueJS v-bind:style binding makes it possible to set CSS variables. I am attempting to create a union type that allows for the object passed to v-bind:style to retain typings for CssStyleDeclaration, while also being relaxed enough to accept an arbitrary property name:

type Dictionary<T> = { [key: string]: T };
type Nullable<T> = T | null;
type CssStyleObject =
  Partial<CSSStyleDeclaration> |
  Dictionary<Nullable<string>>;

Here is an example implementation (view live code on TypeScript playground):

<!-- Template -->
<div v-bind:style="myStyle"></div>
// Component code
@Component
export default class MyComponent extends Vue {
  public get myStyle(): CssStyleObject {
    const style: CssStyleObject = { };
    style.backgroundColor = 'red';
    style['--my-custom-css-property'] = '16px';
  }
}

When I have the noImplicitAny flag enabled (which cannot be turned off due to project-wide configuration), a type error occurs because of:

Element implicitly has an 'any' type because type 'CssStyleObject' has no index signature.

A solution has been suggested here, but I prefer to avoid simply casting to any if there is an alternate viable solution available.

The interesting thing is, the error disappears when using a custom property name with the assignment to the style variable:

const style: CssStyleObject = {
    '--foobar': '50%'
};
style.backgroundColor = 'red';
style['--my-custom-css-property'] = '16px';

View the code above on TypeScript Playground.

This happens perhaps because the type for style is then modified to simply be Dictionary<string> instead of the union type, preventing further errors from occurring.


Update and Solution

It appears that I incorrectly confused intersection and union types in TypeScript. In this case, the CssStyleObject should be an intersection of

Partial<CSSStyleDeclaration>
and
Dictionary<Nullable<string>>
, as shown below:

type Dictionary<T> = { [key: string]: T };
type Nullable<T> = T | null;

// Use `&` to create an intersection type!
type CssStyleObject =
  Partial<CSSStyleDeclaration> &
  Dictionary<Nullable<string>>;

Answer №1

Initially, the reason behind the current behavior of your code lies in how discriminated union types function. CSSStyleDeclaration lacks an index signature, unlike Dictionary. Hence, when you introduce a custom property in the declaration, the type is recognized as Dictionary.

Moreover, it's advisable not to utilize a union type if you intend to add an index to an existing type. It's recommended to use an intersection type instead. In other words, CssStyleObject represents a CSSStyleDeclaration with an index signature, rather than just any object that is either a CssStyleObject or possesses an index signature.

Finally, below is a functional code snippet:

type CssStyleObject = Partial<CSSStyleDeclaration> & Record<string, string | null>
// alternatively
interface CssStyleObject extends Partial<CSSStyleDeclaration> {
    [key: string]: string | null
}

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

Classbased Typescript implementation for managing state with a Vuex store

Hey everyone, I'm currently working on a Vue project with Vuex using decorators for strong typing in my template. As someone new to the concept of stores, I am struggling to understand how to properly configure my store to work as expected in my comp ...

Issues with integrating VUE frontend with PHP backend and API

Apologies for any language mistakes as English is not my native tongue. I hope my message is clear enough. We are in the process of developing a user system where users, upon logging in, can perform various actions such as joining events, updating their p ...

Guide to setting up a Cordova and TypeScript project using the command line interface

For my mobile application development, I rely on Cordova and execute cordova create MyApp in the command-line to initiate a new project. I am familiar with JavaScript but now require TypeScript for my project. Please assist me in setting up a Cordova pro ...

Creating a full-width tab card with Bootstrap-Vue: A step-by-step guide

I stumbled upon something similar in the documentation for bootstrap-vue: A card with tabs: https://i.sstatic.net/HoVEC.png Now, how can I style the tabs to look like this: https://i.sstatic.net/dbsRj.png This is my current code: <b-card no-body ...

Having trouble with Typescript in React and Firestore? Wondering why you are receiving the error message "Variable 'l' implicitly has type 'any[]' in some locations where its type cannot be determined.ts"?

For my To Do List project, I am utilizing Next.js/React with Firebase as the backend. The task items consist of name, time required for task completion, and due date fields. My goal is to retrieve the items from the Firebase collection and set them in setD ...

Error TS2346: The parameters provided do not match the signature for the d3Service/d3-ng2-service TypeScript function

I am working with an SVG file that includes both rectangular elements and text elements. index.html <svg id="timeline" width="300" height="100"> <g transform="translate(10,10)" class="container" width="280" height="96"> <rect x ...

"Upon submitting a form in React JS, the components will automatically trigger a

Within my application, there is a Mobx storage in conjunction with a modal window component. The form within the modal window allows me to collect all the properties and push them into an array named 'cart' within the storage as an object. Take a ...

Error in Ionic Cordova Build prod: Module "." not found - Requires Typescript version >3

After updating my ionic project and all dependencies, I encountered an error when trying to build a --prod android apk: Uncaught Error: Cannot find module "." at vendor.js:1 at vendor.js:1 at Object.<anonymous> (vendor.js:1) at e (vendor.js:1) at Ob ...

Incorrect typings being output by rxjs map

combineLatest([of(1), of('test')]).pipe( map(([myNumber, myString]) => { return [myNumber, myString]; }), map(([myNewNumber, myNewString]) => { const test = myNewString.length; }) ); Property 'length' does not ...

Find all objects in an array that have a date property greater than today's date and return them

I have an array of objects with a property called createdDate stored as a string. I need to filter out all objects where the createdDate is greater than or equal to today's date. How can this be achieved in typescript/javascript? notMyScrims: Sc ...

Typescript error TS2717: All following property declarations should share the same data type

During development on my local host, the TypeScript build works perfectly fine. However, when transitioning to Docker with a Node image, I encounter a peculiar error during the build process: src/middlewares/auth.ts(16,13): error TS2717: Subsequent propert ...

Automatically restarting Vue when utilizing fs.writeFile within socket.io

Whenever a client uploads an image, they should use the following code to emit it: var image= { imageData: {base64:dataurl}, } socket.emit("Toserver", image) In Vue, there is always a restart when running npm run dev. On the server side: socket.on(&a ...

Attempting to iterate through the div in order to collect all of the checkboxes and assign a label to each one

I am attempting to modify a piece of JavaScript code in order to locate all checkboxes, assign names to them, and then add label attributes with CSS for accessibility purposes. Here is the snippet of my existing code: <tr class="el-table__row" ...

Error in TypeScript: Objects can only specify properties that are known, and 'state' is not found in type 'Partial<Path>'

As I strive to pass props through a React Router Link, my goal is to include all the user props. The code below is causing an error, particularly where state: {...employee} is highlighted. Although I am relatively new to TypeScript, I am actively working ...

I'm encountering an issue with enabling Node.js support on PhpStorm as it keeps freezing at the dialog box. Does anyone have a solution for this problem?

Seeking assistance with configuring code support for Vue files in PhpStorm v10.0. Despite having Node and Vue plugins installed, my laptop also has Node(v10.16.3) downloaded. Encountering an issue where PhpStorm freezes at a dialog box, as shown in the sc ...

ngPrime table column selection and data extraction

I am looking to extract multiple columns from a table. Can anyone suggest the best approach for this? Does NGPrime offer any functionality for achieving this task? Appreciate your help! ...

"Troubleshooting: The unique key prop is not functioning as expected with a

I am continuously receiving the warning message: Each child in a list should have a unique "key" prop. Even though I have assigned a key with an index number to my element, it does not appear in the HTML when inspecting via dev tools. The key values are a ...

What are the alternative ways to incorporate ES6 modules into a Node program if we do not specify "type" : "module" in the package.json file?

Currently, I am facing an issue with my server (built on NodeJS) and client (developed using Vue and compiled with vue-cli) sharing some common code. The problem arises because Vue does not support the "type": "module" option, making it ...

How can Vue handle passing an array in this scenario?

In my code snippet, I am attempting to build a simple form builder application. The goal is to include multiple select fields in the form. I encountered a problem with passing an array into a loop. Despite my efforts, the code did not work as expected. Ho ...

Angular 13 implementation of a double-loop structure for fetching data from an API

I'm facing an issue with retrieving specific data fields label and svm from a JSON file. The desired fields are nested inside PORTFOLIO > REGROUPEMENT > ELEMENT. You can access the JSON file here. img(1) I've attempted to display the dat ...