You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Type narrowing doesn't behave as I expect it would for a union of interfaces where one property type is mapped directly to another property type. If this is not a bug, I would love to understand how I can better type this use case because it appears valid to me.
enum FooKeys {
BAR = 'bar',
BAZ = 'baz'
}
interface Bar {
key: FooKeys.BAR;
value: string;
}
interface Baz {
key: FooKeys.BAZ;
value: number;
}
type Foo = Bar | Baz;
interface FooBar {
bar: Bar['value'],
baz: Baz['value'],
opts: Foo[]
}
class FooBar implements FooBar {
bar = 'abc';
baz = 123;
opts: Foo[] = [{
key: FooKeys.BAR,
value: 'def'
},
{
key: FooKeys.BAZ,
value: 456
}
];
constructor(){ }
foobar(): void {
this.opts.forEach(({ key, value }) => {
// Throws error:
// Type 'string | number' is not assignable to type 'never'.
// Type 'string' is not assignable to type 'never'.
this[key] = value;
});
}
}
🙁 Actual behavior
The Foo properties of value and key are not narrowed relative to each other despite being constituents of discrete types where they are directly related.
🙂 Expected behavior
I would expect that typing an object as Foo would enforce the relationship between the key and value properties. This is because the Foo union is not an any to any relationship of its constituent interfaces' properties. Each interface has a type for the key which maps directly to a type for the value. These relationships are enforced at the time of initializing opts: Foo[] but that same reasoning seems to not apply when narrowing and gating the Foo objects.
The text was updated successfully, but these errors were encountered:
enumInvalidReason{ERROR_1,ERROR_2,}interfaceEvaluatedDayBase{day: string;isValid: boolean;invalidReason: InvalidReason|null;}interfaceValidEvaluatedDayextendsEvaluatedDayBase{isValid: true;invalidReason: null;}interfaceInvalidEvaluatedDayextendsEvaluatedDayBase{isValid: false;invalidReason: InvalidReason;}typeEvaluatedDay=ValidEvaluatedDay|InvalidEvaluatedDay;functiongetEvaluatedDay(): EvaluatedDay{leterror: InvalidReason|null=null;// Types of property 'isValid' are incompatible. Type 'boolean' is not assignable to type 'false'.(2322)// with isValid = true and invalidReason = null, I would expect Typescript to see this as `ValidEvaluatedDay`return{day: '2022-10-31',isValid: error===null,invalidReason: error,};// below code works as expected though/* return { day: '2022-10-31', ...(error === null ? { isValid: true, invalidReason: null } : { isValid: false, invalidReason: error }), }; */}
Bug Report
Type narrowing doesn't behave as I expect it would for a union of interfaces where one property type is mapped directly to another property type. If this is not a bug, I would love to understand how I can better type this use case because it appears valid to me.
🔎 Search Terms
enum, union, type, interface, property, never, error, validation, gating, narrowing, 4.7.4, strict
🕗 Version & Regression Information
Bug appears in v4.7.4 (used in my context) through latest
next
version today.⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
The
Foo
properties ofvalue
andkey
are not narrowed relative to each other despite being constituents of discrete types where they are directly related.🙂 Expected behavior
I would expect that typing an object as
Foo
would enforce the relationship between thekey
andvalue
properties. This is because theFoo
union is not anany
toany
relationship of its constituent interfaces' properties. Each interface has a type for thekey
which maps directly to a type for thevalue
. These relationships are enforced at the time of initializingopts: Foo[]
but that same reasoning seems to not apply when narrowing and gating theFoo
objects.The text was updated successfully, but these errors were encountered: