How to replace all return type from class intypescript - typescript-generics

I want to change methods return type for implement RPC.
class Original {
hello(): number;
world(a: number): string;
}
Class Magic<T> {
...(something I want...)
}
new Magic<Original>()
// => likely
{
hello(): Promise<number>;
world(a: number): Promise<string>;
}
How to make it?
Thanks.

There is a slightly round about way to achieve this -
class Original {
hello(): number { return 2 }
world(a: number): string { return "str" }
}
type Magic<T> = {
[K in keyof T]:
T[K] extends (...args:any[]) => any ? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>> : never
}
type IMagic = Magic<Original>
class OtherClass extends IMagic {
// implement your methods here
}
Playground

Related

Symfony Zenstruck Foundry embedded entity without duplicated property

I have an entity MultiChannel that has a OneToMany relation with SalesChannel.
The restriction is that MultiChannel cannot have 2 SalesChannels that have the same name property.
Initially I had created the Story below, but that will endup with SalesChannels that have the same name.
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => SalesChannelFactory::randomRange(1,3),
];
});
}
}
Then I created a SalesChannelStory as below:
App/Tests/Story/SalesChannelStory
final class SalesChannelStory extends Story
{
public function build(): void
{
$this->addToPool('name1', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[0]])->many(50));
$this->addToPool('name2', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[1]])->many(50));
$this->addToPool('name3', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[2]])->many(50));
$this->addToPool('name4', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[3]])->many(50));
}
}
The intention was to do something as below on MultiChannelStory, in somewhat pseudo code, so that
I could insert only uniquely named SalesChannel into MultiChannel:
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => $this->getUniqueNamed(),,
];
});
}
}
private function getUniqueNamed(): \App\Entity\Onetomanybi|\Zenstruck\Foundry\Proxy
{
// get up to 4 SalesChannel without the property `name` being repeated.
$items = [SalesChannelStory::getRandom('name1'), SalesChannelStory::getRandom('name2')];
return $items;
//return SalesChannelStory::getRandom('name1');
}
But that does not work.
Note that MultiChannel has to have at least one SalesChannel, up to as many SalesChannel exists, or 4 currently.

In NestJS, how to get execution context or request instance in custom method decorator?

I have a custom method decorator like this.
export function CustomDecorator() {
return applyDecorators(
UseGuards(JwtAuthGuard)
);
}
Inside the Custom Decorator, I want to get the Request Header but not sure how to get the Request Instance?
You won't be able to get the ExectuionContext object or the Request object in a class or method decorator, because these decorators are run immediately at the moment of import. What should be done instead is to make a SuperGuard that does have the ExecutionContext available to it. This SuperGuard should have all of the other guards injected into it via the constructor and depending on the header you should call/return the result from the guard called. Something like this:
#Injectable()
export class SuperGuard implements CanActivate {
constructor(
private readonly jwtAuthGuard: JwtAuthGuard,
private readonly googleAuthGuard: GoogleAuthGuard,
) {}
canActivate(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
if (req.headers['whatever'] === 'google') {
return this.googleAuthGuard.canActivate(context);
} else {
return this.jwtAuthGuard.canActivate(context);
}
}
}
I managed to access the execution context within decorator using Inject inside decorator's factory.
Here is my decorator that swallows errors produced by method and returns predefined value in case of exception.
import { Injectable, Scope, Inject, ExecutionContext } from '#nestjs/common';
import { CONTEXT } from '#nestjs/graphql';
#Injectable({ scope: Scope.REQUEST })
export class ExceptionsHandler {
public constructor(#Inject(CONTEXT) private readonly context: ExecutionContext) {}
private integrationsRequestErrors: unknown[] = [];
public handle(error: unknown): void {
// ADD error to context if necessary
this.integrationsRequestErrors.push(error);
}
}
export const ErrorSwallower = (options: {
serviceImplementation: string;
defaultValue: unknown;
errorMessage?: string;
}): MethodDecorator => {
const { defaultValue, integration } = options;
const Injector = Inject(ExceptionsHandler);
return (target: object, _propertyKey: string, descriptor: PropertyDescriptor) => {
Injector(target, 'exceptionsHandler');
const originalMethod = descriptor.value;
descriptor.value = function (...args: unknown[]) {
const exceptionHandler = this.experiment as ExceptionsHandler;
try {
const result = originalMethod.apply(this, args);
if (result && result instanceof Promise) {
return result.catch((error: unknown) => {
exceptionHandler.handle({ error, integration });
return defaultValue;
});
}
return result;
} catch (error) {
exceptionHandler.handle({ error, integration });
return defaultValue;
}
};
};
};
and here is the code above put into action:
#Injectable()
export class ExampleService {
#ErrorSwallower({ serviceImplementation: 'ExampleClass', defaultValue: [] })
private async getSomeData(args: IGetSomeDataArgs): Promise<ISomeData[]> {
throw new Error('Oops');
}
}

How to implement class in TypeScript?

Could you help me to create class 'MyClass'
class M should be Newable and implement IMyInterface
export interface IMyInterface<A>
{
SomeData : A;
}
export class MyClass<T,M inherits IMyInterface<T> and new() >
{
list = new Array<M>();
privete Creator()
{
const obj = new M();
obj.SameData = 'Hello data';
list.push( obj );
}
}
Think you're looking for something like this...
export interface IMyInterface<A> {
SomeData: A;
}
export class MyClass<T, M extends IMyInterface<T>> {
private list: M[] = [];
constructor(private constructorFunction: {new(): M; }) {
}
public add(item: T): void {
const obj = new this.constructorFunction();
obj.SomeData = item;
this.list.push(obj);
}
}
export class MyItem implements IMyInterface<string> {
public SomeData: string = '';
}
const collection = new MyClass<string, MyItem>(MyItem);
collection.add('Hello data');
I've tweaked your psuedocode so that it actually compiles and does what I think you were aiming for in the question. The important thing to note is that the types in TypeScript have no representation at runtime so you can't do new T(). Instead you need to pass in the constructor function for your class which has a type of { new(): M; }. You can then do a new X() with this value to get an object which extends your interface.

HTTP : Detect changes in child component when update/save/delete

I'm learning HTTP as I go. Unsure how to move forward. I'm doing http calls only in my service.
Then I have a class, Teacher, here's some of the methods:
export class Teacher {
public addStudent(value: Student): void {
this.students.push(value);
}
}
I have a list component that lists teachers, and in that component, the user can click a teacher and move to a detail-page, where it takes user input and adds students to the teacher.
export class TeacherDetailComponent implements OnActivate {
teacher: Teacher;
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(curr: RouteSegment): void {
let id = curr.getParam('id');
this._service.getById(id)
.subscribe(teacher => {
this.teacher = teacher;
});
}
addStudent() {
this.teacher.getStudents().push(new Student());
//what code here?
}
}
There is my headscratcher, how and where do I tell Angular that to update the data for the teacher when a new student is added!
In fact your question is related to component communication. I would create a shared service for this.
See this doc for more details:
https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
So I would create a service to notify the list component that a student is added or remove, so it can update the list accordingly. Here is a sample:
#Injectable()
export class StudentService {
userAdded:Subject<Student> = new Subject();
userDeleted:Subject<Student> = new Subject();
constructor(private http:Http) {
}
addStudent(student:Student) {
return this.http.post('/users', ...)
(...)
.do((addedStudent) => {
this.userAdded.next(addedStudent);
});
}
deleteStudent(student:Student) {
return this.http.post('/users', ...)
(...)
.do((removedStudent) => {
this.userRemoved.next(removedStudent);
});
}
}
So you can update your details component:
addStudent() {
let newStudent = new Student();
this.studentService.addStudent(newStudent).subscribe(addedStudent => {
this.teacher.getStudents().push(addedStudent);
});
}
In the list component:
this.studentService.addedStudent.subscribe(addedStudent => {
// do something
});

Robolectric packagemanager doesn't return correct value for getNameForUid?

I keep getting null, even though the package is added. I looked at the source, turns out StubPackageManager is always returning null for that and there is no way to override the entire PackageManager class.
In setup:
MockPackageManager mockPackageManager = new MockPackageManager(
Robolectric.getShadowsAdapter());
RuntimeEnvironment.setRobolectricPackageManager(mockPackageManager);
Subclass:
class MockPackageManager extends DefaultPackageManager {
public MockPackageManager(ShadowsAdapter shadowsAdapter) {
super(shadowsAdapter);
}
#Override
public String getNameForUid(int uid) {
switch (uid) {
case UID_A:
return NAME_A;
case UID_B:
return NAME_B;
default:
return null;
}
}
#Override
public boolean isPermissionRevokedByPolicy(String s, String s1) {
return false;
}
}

Resources