Open
Description
TypeScript Version: 2.4.1
Code
function create_my_class<T>() {
return class {
value: T;
constructor(
value: T
) {
this.value = value;
}
}
}
const MyClassWithNumber = create_my_class<number>();
const with_number = new MyClassWithNumber(234);
with_number.value = 10;
// with_number.value = "sdf"; // error, and rightly so
const something: any = with_number;
if(something instanceof MyClassWithNumber) {
something.value = 20;
something.value = "sdf"; // not an error, but should be one
}
Expected behavior:
The last assignment should be marked as a type error by TS.
Actual behavior:
The last assignment is not marked as error. This is somewhat surprising, as the line
with_number.value = "sdf";
is righteously reported as a type error by TS.
Not a huge issue, but prevented me from using a class factory.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
ikatyang commentedon Jul 18, 2017
It seems working as intended to me (the behavior of
instanceof
), sincesomething instanceof MyClassWithNumber
can only ensuresomething
is an instance of theAnonymous class
, there is no types at runtime (instanceof
), thus TS just narrowsomething
toAnonymous class<any>
(T
->any
), which is the actual behavior, though it'll cause implicitany
.If you still considered this is not the expected behavior, you may have to use something like this:
NOTE: TypeScript is a structural type system, which means
For nominal type matching, see FAQ and #202.
pbazant commentedon Jul 18, 2017
Thank you for your reply. I still have the impression that it would not be an error if TS narrowed the type without the myInstanceOf wrapper.
Quoting from the docs regarding instanceof type guards:
(emphasis added)
N.B. that TS does narrow the type when the function producing the anonymous class is not generic:
So the type of the property seems only to be forgotten (widened to any) when the class ctor is produced by a generic function and there is a "type roundtrip" involving a cast to any followed by an instanceof type guard.
The generic function myInstanceOf compiles to a function that trivially forwards the arguments to the JS instanceof operator, so i'd expect that TS could safely apply the narrowing logic on its own without the need to be taught it by means of myInstanceOf.
In any case, thank you for the myInstanceOf workaround, it works nicely.
kevincox commentedon Apr 21, 2023
I ran into this and was incredibly surprised. This is a dangerous way for
any
to get into your code invisibly.instanceof
is usually a very safe way to type check as it has a reliable runtime check but this makes it unsafe to use on any type with generic parameters. I would expect thatinstanceof
only allows the minimum but instead it usesany
.Basically TypeScript is far too generous here. I would expect it to assume the minimum bound (
unknown
andnumber
in these cases) but it assumes the upper bound!This would be a breaking change so the default probably can't be change but I would definitely like to see a compiler option to do the safer thing in this case. (I looked for this option before finding this issue, I'm surprised it doesn't exist).
joshuakb2 commentedon Jul 13, 2023
I would also appreciate a compiler option to improve this behavior. Right now I'm working around the issue by using a type guard function instead of the
instanceof
keyword. For example, and to extend @kevincox's code example above:joeedh commentedon Nov 26, 2024
Is there any interest in a PR implementing a compiler option as discussed? Is it possible for a dev to chime in?
joeedh commentedon Nov 26, 2024
I think this is the code that'd need to change, from checker.ts:
Could be:
any
type afterinstanceof
#60810maximan3000 commentedon Feb 9, 2025
Found temporary solution, which works fine for me - creating duplicated non-generic class with inheritance
looks like this
Link to sandbox