You can currently do it much better this way (TypeScript 3.9):
// tslint:disable-next-line: no-any
type Constructor<T> = new (...args: any[]) => T;
export function ofType<TElements, TFilter extends TElements>(
array: TElements[],
filterType: Constructor<TFilter>
): TFilter[] {
return <TFilter[]>array.filter(e => e instanceof filterType);
}
Example usage:
class ClassA { }
class ClassB { }
const list: ClassA[] = [new ClassA(), new ClassB()];
const filteredList = ofType(list, ClassB);
Answer from Stephen Weatherford on Stack OverflowYou can currently do it much better this way (TypeScript 3.9):
// tslint:disable-next-line: no-any
type Constructor<T> = new (...args: any[]) => T;
export function ofType<TElements, TFilter extends TElements>(
array: TElements[],
filterType: Constructor<TFilter>
): TFilter[] {
return <TFilter[]>array.filter(e => e instanceof filterType);
}
Example usage:
class ClassA { }
class ClassB { }
const list: ClassA[] = [new ClassA(), new ClassB()];
const filteredList = ofType(list, ClassB);
As Judah pointed out it is unlikely to be possible using generic types alone. I found a workaround where I send in one more parameter with the type...
function OfType<T, U>(list: T[], arg: Function) : U[]
{
var result: U[] = [];
list.forEach(e => {
// extract the name of the class
// used to match primitive types
var typeName = /function\s*([^(]*)/i.exec(arg+"")[1].toLocaleLowerCase();
var isOfType = typeof(e) === typeName;
// if it is not primitive or didn't match the type
// try to check if it is an instanceof
if (!isOfType)
{
try {
isOfType = (e instanceof arg)
}
catch (ex) { }
}
if (isOfType)
result.push(<U><any>e);
});
return <any[]>result;
}
Usage:
var numbers = OfType<any, number>(list, Number);
var foos = OfType<any, Foo>(list, Foo);
alert("Numbers: " + numbers);
alert("Foos: " + foos);
Little redundancy, if someone know a way to remove this redundancy please leave a comment or edit this code.
Or, for primitive types only I could use filter as Judah mentioned.
instanceOf parametrization
Generic types not narrowed with instanceof guard
typescript - Infer class generics when using `instanceof` - Stack Overflow
Create instance of generic type T
You can't do new T() because generics only exist in TypeScript, and there is no way to translate this to Javascript. However, you can do something similar with minor modifications.
abstract class BaseModel {
constructor() {
console.log('BaseModel constructor');
}
public abstract doSomething(x: string): string;
}
class AModel extends BaseModel {
constructor() {
console.log('constructor A');
super();
}
public doSomething(x: string) {
return `doSomething A: ${x}`;
}
}
class BModel extends BaseModel {
constructor() {
console.log('constructor B');
super();
}
public doSomething() {
return 'doSomething B';
}
}
class Operator<T extends BaseModel> {
constructor(private readonly _createClass: {new (): T}) {}
receiveX(): string {
return 'x received';
}
createSomething(): T {
const x = this.receiveX();
// Code that's obviously not working:
const model = new this._createClass();
model.doSomething(x);
return model;
}
}
const aOperator = new Operator(AModel);
const aModel = aOperator.createSomething();
const bOperator = new Operator(BModel);
const bModel = bOperator.createSomething();Edits: trying to get code to format.
Edit2: here is a quick stackblitz
More on reddit.comHi,
I am puzzled on how to implement the pseudocode below.
function search(array:Array<any>, type:Function) {
for(let obj of array) {
if(obj instanceof type)
return obj
}
return null
}
search([123, "333", true], String) => should return "333"
Anyone knows how to parametrize the right side of instanceof?
is it even possible in typescript?
Thank you
As @TobiasS. and @MuratKaragöz pointed out, the instanceof operator can not distinguish Foo and F at runtime, hence the generics are not passed down.
There are two paths to fixing this:
Using instanceof only
Unsafe at runtime
Instead of typing F with typeof Foo<number> as I did. We can create a new constructor type which return an instance of Foo<number>:
class Foo<T = number> {
foo: T;
constructor(foo: T) {
this.foo = foo;
}
}
const F: new (...args: ConstructorParameters<typeof Foo<number>>) => Foo<number> = Foo
let f: unknown = new F(0)
if (f instanceof F) {
f.foo; // number
}
This is a very simple way of typing F, but it IS unsafe at runtime because it tricks Typescript into thinking Foo and F are not the same class, even thought (new Foo()) instanceof F returns true at runtime (see the safer method below).
Although, this trick can still be useful in few niche cases (I personally ended up using a combination of the safe and unsafe methods).
Safe at runtime
This is most likely the preferred solution, as it does not suffer from the same caveat as the unsafe solution above.
Put simply, we can create a new class F which extends Foo<number>:
class Foo<T = number> {
foo: T;
constructor(foo: T) {
this.foo = foo;
}
}
class F extends Foo<number> {
constructor(...args: ConstructorParameters<typeof Foo<number>>) {
super(...args)
}
}
let f: unknown;
if (f instanceof F) {
f.foo; // number
}
This IS safer because (new Foo()) instanceof F will return false at runtime, on the opposite of the unsafe solution.
Using type guards
See @TobiasS.'s and @MuratKaragöz's answers.
- https://stackoverflow.com/a/74626164/8990411
- https://stackoverflow.com/a/74626118/8990411
You could use typeguards e.g
function isF(isF: unknown): isF is Foo<number>{
return isF instanceof F;
}
if (isF(f)) {
f.foo; // Foo<number>
}
I'm having a class hierarchy similar to the following example. First I have some classes that all inherit from one base class. The have doSomething methods that perform some class-specific task that changes properties of the specific instance.
abstract class BaseModel {
...
public abstract doSomething();
}
class AModel extends BaseModel {
...
public doSomething(x) {
// change AModel instance based on x
}
}
class BModel extends BaseModel {
...
public doSomething(x) {
// change BModel instance based on x
}
}
Then I have some generic class that should be able to operate on all child classes. It receives some value "x" from a database that should be used to call the class-specific doSomething method. Then the instance of the specific class should be returned:
abstract class Operator<T extends BaseClass> {
...
createSomething(): T {
const x = this.receiveX();
// Code that's obviously not working:
const model = new T();
model.doSomething(x);
return model;
}
}The call should then work as follows:
const operator = new Operator<AModel>(); const aModel = operator.createSomething();
Now I have found out that instantiating an object using new T() is not possible in Typescript. I'm wondering if there is a workaround though. I'd really like to keep the generic aspect of the Operator class. Does anyone have an idea on how to do this?
You can't do new T() because generics only exist in TypeScript, and there is no way to translate this to Javascript. However, you can do something similar with minor modifications.
abstract class BaseModel {
constructor() {
console.log('BaseModel constructor');
}
public abstract doSomething(x: string): string;
}
class AModel extends BaseModel {
constructor() {
console.log('constructor A');
super();
}
public doSomething(x: string) {
return `doSomething A: ${x}`;
}
}
class BModel extends BaseModel {
constructor() {
console.log('constructor B');
super();
}
public doSomething() {
return 'doSomething B';
}
}
class Operator<T extends BaseModel> {
constructor(private readonly _createClass: {new (): T}) {}
receiveX(): string {
return 'x received';
}
createSomething(): T {
const x = this.receiveX();
// Code that's obviously not working:
const model = new this._createClass();
model.doSomething(x);
return model;
}
}
const aOperator = new Operator(AModel);
const aModel = aOperator.createSomething();
const bOperator = new Operator(BModel);
const bModel = bOperator.createSomething();
Edits: trying to get code to format.
Edit2: here is a quick stackblitz
"When creating factories in TypeScript using generics, it is necessary to refer to class types by their constructor functions. "
https://www.typescriptlang.org/docs/handbook/2/generics.html#using-class-types-in-generics
see also:
https://www.typescriptlang.org/docs/handbook/2/classes.html#abstract-construct-signatures
Edit: I know that instanceof checks at runtime, I'm very familiar with it and have been using it for many years. My question is specifically how the typing system works in typescript, how/why typescript is able to discern via type inference the difference between Error and PseudoError. And, given that it can, whether it is possible to leverage that kind of discernment to create a utility function that's based on this rather than based on shapes and interfaces.
In lib.es5.d.ts in typescript we have:
interface Error {
name: string;
message: string;
stack?: string;
}Now in my typescript file, if I create a new type, like this:
class PseudoError {
name = "hello"
message = "world"
stack? = "friends"
}And I do the following:
const test : PseudoError | Error = new PseudoError() type withoutError = Exclude<typeof test, Error> // <--- results to never, because of duck typing ?
The above is expected, because PseudoError and Error implement the same interface. So if I'm excluding Error, then I'm also excluding PseudoError by duck type standards.
But when I do this:
if (test instanceof Error) {
test // <--- hover over = Error
} else {
test // <--- hover over = PseudoError
}
It suggests that there is obviously some built-in functionality in typescript that doesn't work like in a duck-type-y way. This clearly aligns with the desired outcome in JS, but in my situation, I would like to have an Exclude<...> utility type that does the same thing as what typescript is doing behind the scenes with instanceof.
For example, where's this NotInstanceOf utility function?
const test : PseudoError | Error = new PseudoError() type withoutError = NotInstanceOf<typeof test, Error> // <--- results to PsuedoError