Home > Back-end >  How to set a variable if the computed property may not exist in Typescript?
How to set a variable if the computed property may not exist in Typescript?

Time:11-30

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

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]
    }
}

CodePudding user response:

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

  • Related