As it is possible to set CSS variables using VueJS v-bind:style
binding, I am trying to create a union type where the object passed to v-bind:style
retains the typings for CssStyleDelcaration
and yet is 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>>;
An example of the implementation is as such (see 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';
}
}
However, I get a type error when I have noImplicitAny
flag enabled (a flag that I cannot be turned off because of a project-wide configuration), because TypeScript then complains about:
Element implicitly has an 'any' type because type 'CssStyleObject' has no index signature.
I've seen a proposed solution here: How do I prevent the error "Index signature of object type implicitly has an 'any' type" when compiling typescript with noImplicitAny flag enabled?, but I would love to avoid simply casting to any
, if there is another viable solution possible.
The funny thing is, the error message goes away once I use a custom property name when assigning to the style
variable:
const style: CssStyleObject = {
'--foobar': '50%'
};
style.backgroundColor = 'red';
style['--my-custom-css-property'] = '16px';
See the code above on TypeScript Playground.
I suspect that is because the type for style
is then somehow modified to be simply Dictionary<string>
instead of the union type, so no further errors will be thrown.
Update and solution
So, it turns out that I inherently confused intersection and union types in TypeScript. In this case, the CssStyleObject
is an intersection of Partial<CSSStyleDeclaration>
and Dictionary<Nullable<string>>
, so this should suffice:
type Dictionary<T> = { [key: string]: T };
type Nullable<T> = T | null;
// Use `&` for creating an intersection type!
type CssStyleObject =
Partial<CSSStyleDeclaration> &
Dictionary<Nullable<string>>;