I have a growing love-hate relationship with TypeScript. I'm in favor of strongly-typed languages, they can save you a lot of grief, and they (typically) make the code easier to read for the next guy. Even if the "next guy" is just you a year later.
I needed a type that says "give me all the valid CSS properties you can use in JavaScript to set a style." And sure, there's a library out there that will give it to you, but I'm avoiding dependencies for ... easy things.
So I did the easy thing and defined CSSAttributes
for the function below with the type above it:
HTMLElement
type CSSAttributes = keyof CSSStyleDeclaration;
// OH NO! An error!
// TS2540: Cannot assign to 'length' because it is a read-only property
function reticulate(
elm: HTMLElement,
attrib: CSSAttributes,
value: string
): void {
elm.style[attrib] = value;
}
So there's some read only properties in there. I already know, at this point, that there's a utility type of Omit<Type, Keys>
so I'll use that to remove the read only props.
type toOmit =
'length'
| 'parentRule'
| 'item'
| 'removeProperty'
| 'setProperty'
| 'getPropertyPriority'
| 'getPropertyValue';
type CSSAttributes = keyof Omit<CSSStyleDeclaration, toOmit>;
// OH NO! Another error!
// TS2322: Type 'string' is not assignable to
// type 'string & (() => IterableIterator<string>)'
elm.style[attrib] = value;
Well that makes sense. Some light digging shows that there's a typeof Symbol.iterator
in there I need to exclude, adding it to toOmit
and it's 100% fixed – I now see in my IDE the type of 'number' is allowed. Yikes, lets remove that too. Finally, a very simple type definition:
type toOmit =
'transform'
| 'getPropertyPriority'
| 'getPropertyValue'
| 'item'
| 'length'
| 'parentRule'
| 'removeProperty'
| 'setProperty'
| typeof Symbol.iterator
| number
type CSSAttributes = keyof Omit<CSSStyleDeclaration, toOmit>;
How could this possibly be more simple? :D Full disclosure, it would have been easier to do this:
// at the command line…
> npm i csstype
// in my code…
import type * as CSS from 'csstype';
type CSSAttributes = keyof CSS.Properties;
It's got some other nice parts to it, which is why I ditched my definition and used the csstype
library.