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
{{ message }}
Repository navigation
Private field check narrows generic class too far #46668
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.
typeConstraint={foo: string}|{bar: number};classMyClass<TextendsConstraint>{
#brand =true;value: T;constructor(value: T){this.value=value;}copyValueFrom(x: object){if(#brand inx){this.value=x.value;}}}constwrappedFoo=newMyClass({foo: "foo"});constwrappedBar=newMyClass({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.
Is there anything we can do to also make writing in the other direction safer?
typeConstraint={foo: string}|{bar: number};classMyClass<TextendsConstraint>{
#brand =true;value: T;constructor(value: T){this.value=value;}writeValueTo(x: object){if(#brand inx){// if x.value is `Constraint`, so we can still do an unsafe writex.value=this.value;}}}constwrappedFoo=newMyClass({foo: "foo"});constwrappedBar=newMyClass({bar: 123});wrappedFoo.writeValueTo(wrappedBar);console.log(wrappedBar.value);// type expects bar, value is foo
Activity
acutmore commentedon Nov 4, 2021
Is there anything we can do to also make writing in the other direction safer?
https://www.typescriptlang.org/play?ts=4.5.0-beta#code/C4TwDgpgBAwg9gOwM7AE4EMCWDhQLxQDeUAZnHAFxQqrYDmUAvlAD5FQBG6qVCArgFsOEVEwDcAWABQ0gCYQAxgBtu0AG7coALyp8EAawRwA7gkkypy9EiRQAsiBgqbAHgAqUCAA9gEBLNt4ZDQsHAA+ImkoaKgAYg4Mf3woND4IcxioDSU0qjcMmIVEGj4FYDhUAAps3Kg3AEpIqUzM4AALTCQAOhroAl6C6MZpKJjjWl8ANXQciDc4Sq8qBydrJBcgmlDgMMbCUZaoLx6ZtOT2zpPZsSgAeluoGaUTWz0kdBJoccxfA6YR5pjCYQaazeYAfT0hhMCEWy0cznWUKMpl27D+mWOvXOHW6AzuDxQmCUSkeJJMEFkf2GFky3ympzmcHBCAgahEcPsCLWLlZ7NQaP2gMO9ygxkQAHJcE8TCk2tAwHBfDhME8QFA3h8vsCADScPi4drqRlQTpQIy4VAQNWPc1skQYmJYk0EC54xk3akAmnSIrBMUYMCQWQAMXIyVZxi5qxslWIZEoUAARAmk0x6uY-SgA+gg5SAEKaAiR6OIuOcbhUACMACYAMzp8zjXPBsNwLr0kGM+aVZt52SF1AZ33FOBKCBdZ50XuB4ODq5pDMElLgaDeSBlWwSrioCV67FmiUJiVQIA