Typescript opposite / reverse operation of "typeof"
Asked Answered
M

2

5

Angular can Query subComponents by Types, which is used in Testing like this:

fixture.debugElement.query( By.directive( ComponentType ) );

Now i wanted to make a function which does this for me:

import { ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Type } from '@angular/core';

export function findSubComponent<T>( fixture: ComponentFixture<any>, componentType: T & Type<any> ): T {
  const subComponentDebugElement = fixture.debugElement.query( By.directive( componentType ) );
  return subComponentDebugElement.componentInstance;
}

Now here comes the problem. My function currently returns typeof ComponentType instead of an actual object of ComponentType and therefore i can not access its properties.

The Type of subComponentDebugElement.componentInstance here is any, so i can just declare the type in the return Type argument (function (): T)

How can i turn T which stands for typeof ComponentInstance in this case into ComponentInstance?

Mercantilism answered 27/1, 2022 at 15:5 Comment(7)
Possibly InstanceType<T> but since I can't easily use your example in a standalone IDE like the TypeScript Playground (link here) then I can't check. – Purveyor
Thanks for providing this. InstanceType seems to be the correct way, but i can not use it since InstanceType<T> Type 'T' does not satisfy the constraint 'abstract new (...args: any) => any'.. any clue on how i can define T further to fullfill those constraints? – Mercantilism
I have approximately zero clue until I have a minimal reproducible example I can just paste into a standalone IDE without unrelated errors, sorry. Maybe someone with angular-test specific knowledge can answer right away. Otherwise you might want to work on either removing third party dependencies from your example code or give the necessary import statements so that things work in the playground, or give a link to an external web IDE project with stuff already configured. Good luck! – Purveyor
Okay maybe I have small but nonzero clue, you might just want findSubComponent<T extends abstract new (...args: any) => any>(... but I still can't test it so πŸ€·β€β™‚οΈ – Purveyor
oh im sorry, as i understood the imports might help you to reproduce it? i added the imports and am now trying to test your solution – Mercantilism
you resolved my issue, it took me longer than it should have, but changing the first line to export function findSubComponent<T extends abstract new (...args: any) => any>( fixture: ComponentFixture<any>, componentType: (T & Type<any>) ): InstanceType<T> { fixed the issue. If you want to post an answer i will accecpt it, otherwise i can also post it myself later, but i will leave you the chance to do it, thanks alot, kind stranger! – Mercantilism
Feel free to post your own answer; I would do it, but I just ran into what looks like a nasty bug in the TypeScript playground, where one of your import statements causes the browser to go bonkers and eat up all CPU: tsplay.dev/w166KN (if you click that be ready to kill the tab) – Purveyor
M
9

InstanceType<T>

As suggested by @jcalz the solution to this was to use InstanceType<T> like this:

type AbstractClassType = abstract new ( ...args: any ) => any;

export function querySubComponent<T extends AbstractClassType>(...): InstanceType<T> {
...
}

use of the AbstractClassType as abstract new ( ...args: any ) => any

Please note that the AbstractClassType might not be needed with your existing type definition, but apparently the generic InstanceType<> needs to use a type with a constructor, otherwise i get the following TS-Error: Type 'T' does not satisfy the constraint 'abstract new (...args: any) => any'.

Mercantilism answered 28/1, 2022 at 16:21 Comment(0)
G
0

Basically the same answer, but more compact

function querySubComponent<T extends abstract new (...args: any) => any>(fixture: ComponentFixture<any>, componentType: T & Type<any>) {
    const subComponentDebugElement = fixture.debugElement.query( By.directive( componentType ) );
    return subComponentDebugElement.componentInstance as InstanceType<T>;
}
Gooseflesh answered 3/12, 2022 at 1:57 Comment(0)

© 2022 - 2024 β€” McMap. All rights reserved.