3
var attributeStr = 'scaleX'

interface CSSTransformsAttr{
   scaleX: number,
   scaleY: number,
   skewX: number,
   skewY: number,
   translateX: number,
   translateY: number
}

How to check if the value of attributeStr is equal to a key in CSSTransformsAttr ?

Why do i ask this?

I want to extends the CSSStyleDeclaration with CSSTransformsAttr. If k is key of CSSTransformsAttr which is 'scaleX' | 'scaleY' | 'skewX' | 'skewY' | 'translateX' | 'translateY', i want to do something different than line (1). See below.

function setStyleAttributes(attrs: { [ k in keyof ( CSSStyleDeclaration & CSSTransformsAttr )]?: any }): void {
    if (attrs !== undefined) {
            Object.keys(attrs).forEach((key: string) => {
                /// how to check if 'key' is from the CSSTransfomsAttr not CSSStyleDeclaration ?
                /// ...
            this.htmlElement.style[key]=  attrs[key]; // (1) if key in keyof CSSStyleDeclaration
        });
    }
}
3
  • Could you edit your post and include the code in the image as text? Please copy and paste it here from your editor, instead of using a screenshot. Commented Jan 13, 2020 at 10:50
  • 1
    Sure ! wait a minute. Commented Jan 13, 2020 at 10:53
  • 1
    please have a look, sir! Commented Jan 13, 2020 at 11:03

3 Answers 3

3

Simply checking keyof is only going to work at compile time, not runtime. You need to store all the keys in an array and check if your value exists in it. This can be done manually:

interface CSSMatrixTransforms{
   scaleX: number,
   scaleY: number,
   skewX: number,
   skewY: number,
   translateX: number,
   translateY: number
};
type CSSMatrixTransformsKey = keyof CSSMatrixTransforms;
const matrixKeys: CSSMatrixTransformsKey[] = [
   'scaleX',
   'scaleY',
   'skewX',
   'skewY',
   'translateX',
   'translateY'
];

Alternatively, you can create a "dummy" object that implements your interface and then call Object.keys on it.

interface CSSMatrixTransforms{
   scaleX: number,
   scaleY: number,
   skewX: number,
   skewY: number,
   translateX: number,
   translateY: number
}
type CSSMatrixTransformsKey = keyof CSSMatrixTransforms;
const dummy: CSSMatrixTransforms = {
   scaleX: 0,
   scaleY: 0,
   skewX: 0,
   skewY: 0,
   translateX: 0,
   translateY: 0
}
const matrixKeys: CSSMatrixTransformsKey[] = Object.keys(dummy) as CSSMatrixTransformsKey[];

Finally, in your code, check if your key exists in the matrixKeys array:

function setStyleAttributes(attrs: { [ k in keyof ( CSSStyleDeclaration & CSSTransformsAttr )]?: any }): void {
    if (attrs !== undefined) {
            Object.keys(attrs).forEach((key: string) => {
                if(matrixKeys.includes(key)) {
                    this.htmlElement.style[key] = attrs[key];
                }

        });
    }
}

Check this out as well.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! Wondering if they can make it as a feature for Typescript in the future.
Yes, that would be very helpful. For the moment, this is the way to accomplish this.
0

With the keyof operator e.g.

var attributeStr: keyof CSSMatrixTransforms = 'scaleX' // ok

var attributeStr: keyof CSSMatrixTransforms = 'scaleX1' // wrong

2 Comments

this is what i tried: var randomStr = randomString(); var attributeStr: keyof CSSMatrixTransforms = randomStr i got failed compile: Type 'string' is not assignable to type '"scaleX" | "scaleY" | "skewX" | "skewY" | "translateX" | "translateY"'.
You have to define the return type of randomString with the same type as attributeStr
0

I came up with the code shown below, I had to add the as to cast them but at least I no longer use the any Type anywhere now.

// we need to exclude readonly & function properties (since they're not writable props)
export type CSSStyleDeclarationReadonly = 'length' | 'parentRule' | 'getPropertyPriority' | 'getPropertyValue' | 'item' | 'removeProperty' | 'setProperty';
export type CSSStyleDeclarationWritable = keyof Omit<CSSStyleDeclaration, CSSStyleDeclarationReadonly>;

Object.keys(this.stylingCss as CSSStyleDeclaration).forEach(cssStyleKey => {
  this.elem!.style[cssStyleKey as CSSStyleDeclarationWritable] = this.stylingCss[cssStyleKey as CSSStyleDeclarationWritable];
});

There you go, no more errors and now it does Type checking correctly

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.