Reputation: 1071
I have this snippet
class J {
constructor(public foo: number) {}
}
class B {
constructor(public bar: string) {}
}
interface Cache {
json?: J;
binary?: B;
}
function test(key: "json" | "binary", data: J | B, obj: Cache) {
obj[key] = data;
}
If you try this code in https://www.typescriptlang.org/play/, the line obj[key] = data;
is having the following error
Type 'J | B' is not assignable to type 'J & B'. Type 'J' is not assignable to type 'J & B'. Property 'bar' is missing in type 'J' but required in type 'B'.
There's obviously something I am missing but I can't figure out what. Any idea?
Upvotes: 2
Views: 1588
Reputation: 4072
Typescript can't tell which property of Cache
you are trying to update, and when in doubt he considers that the value you are trying to insert should be able to fit both. Which the J | B can't.
You could change your test
function signature slightly to use Partial
function test(update: Partial<Cache>, obj: Cache) {
Object.assign(obj, update);
}
That way Typescript can be sure that the key/value pairs you are passing it are valid for the Cache
class.
Upvotes: 3
Reputation: 250036
There is no relation between key
and data
, so you could call test with test( "json", new B())
and the assignment would not be valid.
If you use a generic type parameter (lets call it K
) for the key and type data
as Cache[K]
, typescript will allow the assignment. (Even though it is still not 100% type safe as K
could be a union and the same issue as described above could happen):
class J {
constructor(public foo: number) {}
}
class B {
constructor(public bar: string) {}
}
interface Cache {
json?: J;
binary?: B;
}
function test<K extends keyof Cache>(key: K, data: Cache[K], obj: Cache) {
obj[key] = data;
}
Upvotes: 4