-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Use Symbol.hasInstance
for instanceof
narrowing, include constructor as part of class structural type
#17360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
any updates? |
I wouldn't recommend this, as it would make it impossible for a subclass to define a constructor with arguments that differ from its base, because the construct signatures of the See this example in the playground for why this wouldn't work. Aside from that, I agree that pairing interface NameMixin {
name: string;
}
const kName = Symbol("kName");
const NameMixin = <TBaseClass extends Constructor>(baseClass: TBaseClass):
TBaseClass & (new (...args: any[]) => MyMixin) => {
abstract class MixinClass extends baseClass implements NameMixin {
private [kName] = "";
get name() { return this[kName]; }
set name(value) { this[kName] = value; }
}
return MixinClass;
};
NameMixin[Symbol.hasInstance] = (obj: unknown) => obj is NameMixin {
return typeof obj === "object" && obj !== null && kName in obj;
};
class Base { }
class Sub extends NameMixin(Base) {}
const s: unknown = new Sub();
if (s instanceof NameMixin) {
// s has type 'NameMixin'
} |
The same problem: type X = string | string[];
const isArray = (type: unknown): type is string[] => {
return Array.isArray(type);
};
if (isArray(x)) {
// Ok
} class isArray {
static [Symbol.hasInstance](type: unknown): type is string[] {
return Array.isArray(type);
}
}
if (x instanceof isArray) {
// TS2345: Argument of type 'string | string[]' is not assignable to parameter of type 'string[]'. Type 'string' is not assignable to type 'string[]'.
}
} It looks like a bug. |
My proposal:
instanceof
expressions, ifSymbol.hasInstance
exists on the RHS, narrow the expression according to the method's return value.constructor
prototype property which istypeof classConstructor
, if such a property was not defined in the class body.The rationale of this is that you can then (via compiler flag) by default define
Symbol.hasInstance
on constructors to type check against their return type (like fornew () => T
, defining[Symbol.hasInstance](x: any): x is T
). This would mostly mitigate a certain unsoundness issue with classes, making the workaround a bit more difficult to do:Notes:
Symbol.hasInstance
is equivalent to legacyinstanceof
.instanceof
should not exclude possible structural type #17344 and would reduce the need for nominal typing (Support some non-structural (nominal) type matching #202) in a common use case.The text was updated successfully, but these errors were encountered: