Open molisani opened 2 years ago
Is there anything we can do to also make writing in the other direction safer?
type Constraint = { foo: string } | { bar: number };
class MyClass<T extends Constraint> {
#brand = true;
value: T;
constructor(value: T) {
this.value = value;
}
writeValueTo(x: object) {
if (#brand in x) {
// if x.value is `Constraint`, so we can still do an unsafe write
x.value = this.value;
}
}
}
const wrappedFoo = new MyClass({ foo: "foo" });
const wrappedBar = new MyClass({ bar: 123 });
wrappedFoo.writeValueTo(wrappedBar);
console.log(wrappedBar.value); // type expects bar, value is foo
Bug Report
Discovered a potential issue with https://github.com/microsoft/TypeScript/pull/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 passany
for all type arguments (see https://github.com/microsoft/TypeScript/issues/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
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
Assignment in
copyValueFrom
proceeded without error, results in mismatch between type and value.π Expected behavior
In
copyValueFrom
, expected brand to narrowx
toMyClass<Constraint>
and report errorType 'Constraint' is not assignable to type 'T'.
when assigningthis.value = x.value
.