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