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>>;