Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to set a variable if the computed property may not exist in Typescript?

When using Computed Property in javascript, I can write my code like this

const def_val = {a:"debug",b:"info",c:"warning"};

function work(y) {
    let x = def_val[y] || def_val.a /* if y is not a or b or c */
}

But how to I make that work in typescript ?

const def_val = {a:"debug",b:"info",c:"warning"};

function work(y: string) {
    let x = def_val[y] || def_val.a;
}

I got the compiler error

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error TS7053: Element implicitly has an ‘any’ type because expression
of type ‘string’ can’t be used to index type ‘{ a: string; b: string;
c: string; }’.

No index signature with a parameter of type ‘string’
was found on type ‘{ a: string; b: string; c: string; }’.

I have searched SO but I can only find How to set a variable if undefined in typescript? which is not my question.

Now I changed my ts code to these, but it feels tedious compared to the original js code

function work(y: string) {
    let x:string
    if (y!='a' && y!='b' && y!='c') {
        x = def_val.a;
    } else {
        x = def_val[y]
    }
}

>Solution :

def_val is infered by typescript as

const def_val: {
    a: string;
    b: string;
    c: string;
}

y argument has string type

def_val expects 'a' | 'b' | 'c' as a keys. It means that typescript allows you to use only these keys with def_val. Since string type is much wider than 'a' | 'b' | 'c' you are getting error.

y:string means that it allows you to pass foo property and def_val['foo'] is not safe since foo does not exists in def_val.

In order to fix it, you should provide explicit type for def_val:

const def_val: Record<string, string> = { a: "debug", b: "info", c: "warning" };

function work(y: string) {
    let x = def_val[y] || def_val.a // ok
}

IF you are not allowed to use explicit type on def_val, you can provide def_val as an argument to work:


const def_val = { a: "debug", b: "info", c: "warning" };

function work<Def extends Record<string, string>>(def: Def, y: string) {
    let x = def[y] || def.a
}
work(def_val, 'foo') // ok

You also can use custom typeguard:


const def_val = { a: "debug", b: "info", c: "warning" };

const isValidKey = (key: string): key is keyof typeof def_val =>
    /a|b|c/.test(key)

const work = (y: string) => isValidKey(y) ? def_val[y] : def_val.a

work('foo') // ok

P.S. Here you can find documentation about using built in utility types , like Record, Partial, etc …

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading