This issue arose as a result of the changes made in Enhancing the integrity of indexed access types. The concern here is not that the specific assignment is inherently flawed, but rather because when you define desired
as MyObject1[T]
, it becomes capable of being assigned to the property value of an object belonging to type MyObject1
by definition. Allowing this assignment could potentially lead to complications elsewhere:
const example = <T extends Tag>(t: T, { value }: MyObject2[T]) => {
// Unexpected type error
// Type 'Foo | Bar' is not assignable to type 'MyObject1[T]'.
const desired: MyObject1[T] = value;
let myObj1!: MyObject1;
myObj1[t] = desired; // This is where issues arise, especially if T can be a union.
}
example<Tag>("foo", { value: { bar: 0 }}); // This call puts myObj1 in an invalid state where myObj1['foo'] will have a type of Bar
If we were to allow MyObject1[T]
to remain a union of potential values and only flag errors during assignments, it would make it impossible to represent 'a value that can be assigned as an object value'. Therefore, the following code snippet would be deemed invalid (and impossible to properly type):
const setProperty = <T extends Tag>(t: T, v: MyObject1[T]) => {
let myObj1!: MyObject1;
myObj1[t] = v; // This assignment would pose issues if MyObject1[T] did not encompass the intersection of all possible values of MyObject1
}
If you aim to depict a union of potential values for an object, utilize MyObject1[Tag]
.
const example = <T extends Tag>(t: T, { value }: MyObject2[T]) => {
const desired: MyObject1[Tag] = value;
}
Depending on your subsequent requirements, you may need a type assertion at some stage. However, without more context from your code, it's challenging to determine whether you can express it sans assertions, if it truly aligns with type safety, or if it's merely a limitation of the type system.