#"in" operator to safely access object property
30 messages · Page 1 of 1 (latest)
Preview:ts type A = { a: string } type B = { b: string } type C = { c: string } const keys = ["a", "b", "c"] as const function myFunction(obj: A | B | C) { for (const [index, key] of keys.entries()) { if (key in obj) { console.log(obj[key]) // ^Element implicitly has an 'any' type because expression of type '"a" | "b" | "c"' can't be used to index type 'A | B | C' ...
well, obj could be of type A, which means it would only have the a property
but then you'd try to access the b and c property using the array
which isn't allowed
If obj is of type A and key is "a" the condition is false and I will not access the property I think ?
yeah, but TS doesn't see it that way
for TS obj is of type A | B | C
and you can't use a key to access a property when you aren't sure it's in that object
what you ned to do is use a type predicate
so you can narrow key
and you'll be sure it will be a key of obj
With type guards do I have to do 3 separate cases here ?
not really
you can simply move the chec in a type predicate function and use that function
Preview:```ts
type A = {
a: string
}
type B = {
b: string
}
type C = {
c: string
}
const keys = ["a", "b", "c"] as const
function myFunction(obj: A | B | C) {
for (const [index, key] of keys.entries()) {
if (isKey(obj, key)) {
console.log(obj[key])
...```
Thanks a lot i was about to do something really dirty 😆
Was about to use this :
type ABC = {
a: string
b: string
c: string
}
function objHasKey(obj: A | B | C, key: Key): obj is ABC{
return key in obj;
}
Because I didn't think of k is keyof typeof o to narrow 🙂
I was trying to narrow obj instead of key 🙃
I have an error still !
With your example key is typed as never
@wicked crater One simple thing you can do here is "upcast" and just make the object a Record<string, string> that you can access (and null check)
function myFunction(obj: A | B | C) {
// Partial can be omitted with --noUncheckedIndexedAccess enabled
const _obj: Partial<Record<string, string>> = obj;
for (const [index, key] of keys.entries()) {
const val = _obj[key];
if(val) {
console.log(val);
}
}
}
Or if you want to be more precise:
const _obj: Partial<Record<"a" | "b" | "c", string>> = obj;
@safe fog thanks for the hint I adopted the upcast, it's still better than using @ts-ignore or a cast 😊