Description
Bug Report
Discovered a potential issue with #44648 in regards to how classes with type parameters are handled. The presence of the brand indicates that the object is an instance of this class, but doesn't say anything about the type arguments. For instanceof
the current behavior is to pass any
for all type arguments (see #17473 for that issue) but the default here should be that the type matches the constraint for that corresponding type parameter.
🔎 Search Terms
ts4.5-beta
, private fields
, brand checks
, generic
, type parameter
, narrowing
🕗 Version & Regression Information
TypeScript Version: ts4.5-beta
- I was unable to test this on prior versions because the feature didn't exist yet.
⏯ Playground Link
Playground link with relevant code
💻 Code
type Constraint = { foo: string } | { bar: number };
class MyClass<T extends Constraint> {
#brand = true;
value: T;
constructor(value: T) {
this.value = value;
}
copyValueFrom(x: object) {
if (#brand in x) {
this.value = x.value;
}
}
}
const wrappedFoo = new MyClass({ foo: "foo" });
const wrappedBar = new MyClass({ bar: 123 });
wrappedFoo.copyValueFrom(wrappedBar);
console.log(wrappedFoo.value.foo); // type expects foo, value is bar
🙁 Actual behavior
Assignment in copyValueFrom
proceeded without error, results in mismatch between type and value.
🙂 Expected behavior
In copyValueFrom
, expected brand to narrow x
to MyClass<Constraint>
and report error Type 'Constraint' is not assignable to type 'T'.
when assigning this.value = x.value
.