TypeScript Conditional Types Good Usage Part 1

Example 1

I try to understand eventType field from Event object. But in order to use createEventGridMessage in other TypeScript file, you need to import StartEvent, InfoEvent and EndEvent types. So next example of this case looks better to me 🙂

import {v4 as uuidv4} from 'uuid';

export type BaseEvent = {
    timeStamp?: number,
    componentName: string,
    componentVersion: string,
    operationId: string,
    correlationId: string,
    data: any,
}

export type StartEvent = Partial<BaseEvent> & {
    eventType: 'LogStart',
    source: string,
    trigger: string,
};

export type EndEvent = Partial<BaseEvent> & {
    eventType: 'LogEnd'
    destination: 'Event Grid' | 'Http Response' | 'Database' | string,
};

export type InfoEvent = Pick<EndEvent, keyof Omit<EndEvent, 'eventType'>> & { eventType: 'LogInfo' };

export type Event = StartEvent | EndEvent | InfoEvent;


export type EventGridMessageParameters<T extends Event> = Pick<EventGridMessage<T>, 'data' | 'eventType' | 'subject' | 'topic'>;

export type EventType<T extends Event> = T extends StartEvent ? 'LogStart' : T extends EndEvent ? 'LogEnd' : T extends InfoEvent ? 'LogInfo' : 'UNKNOWN EVENT TYPE';

export interface EventGridMessage<T extends Event> {
    id: string;
    topic: string;
    subject: string;
    eventType: EventType<T>;
    eventTime: Date;
    data: T;
    dataVersion: string;
    metadataVersion: string;
}

export const createEventGridMessage = <T extends Event>({
                                                            data,
                                                            eventType,
                                                            subject = "New message from unknown source",
                                                            topic = ""
                                                        }: EventGridMessageParameters<T>): EventGridMessage<T> =>
    ({
        id: uuidv4(),
        topic,
        subject,
        eventType,
        eventTime: new Date(),
        data: {...data, timeStamp: data.timeStamp || new Date().getTime()},
        dataVersion: "1.0",
        metadataVersion: "1.0"
    });


const startLogMessage = createEventGridMessage<StartEvent>({
    eventType: 'LogStart',
    data: {
        eventType: 'LogStart',
        trigger: '',
        source: '',
        correlationId: '',
        componentVersion: '',
        componentName: '',
        operationId: ''
    },
    subject: '',
    topic: ''
});
console.log(startLogMessage);


const infoLogMessage = createEventGridMessage<InfoEvent>({
    eventType: 'LogInfo',
    data: {
        eventType: 'LogInfo',
        correlationId: '',
        componentVersion: '',
        componentName: '',
        operationId: '',
        destination: '',
    },
    subject: '',
    topic: ''
});
console.log(infoLogMessage);


const endLogMessage = createEventGridMessage<EndEvent>({
    eventType: 'LogEnd',
    data: {
        eventType: 'LogEnd',
        timeStamp: new Date().getTime(),
        correlationId: '',
        componentVersion: '',
        componentName: '',
        operationId: '',
        destination: '',
    },
    subject: '',
    topic: ''
});
console.log(endLogMessage);
Continue reading

TypeScript Conditional Types

Conditional Type Expression

SomeType extends OtherType ? TrueType : FalseType;

Basic Usages

Example 1

type NumberOrNot<T> = T extends number ? string : never;

Example 2

type StringOrNot<T> = T extends string ? string : never;

Example 3

type BooleanOrNumberOnly<T> = T extends boolean | number ? T : never;

type NewType = StringOrNumberOnly<string | number | boolean>;

const a1: NewType = true; // boolean

const a2: NewType = 23; // number
Continue reading

Jest Mocking Default Instance

Example 1

const mockedPutObject = jest.fn();

jest.mock('@aws-sdk/client-s3', () => {
    return {
        S3: jest.fn(() => ({
            putObject: () => mockedPutObject()
        }))
    }
});

Example 2

jest.mock('uuid', () => ({ v4: () => '00000000-0000-0000-0000-000000000000' }));

Example 3

jest.mock('uuid');

const mockedUuidv4 = uuidv4 as jest.Mock;

mockedUuidv4.mockReturnValue('00000000-0000-0000-0000-000000000000');

Example 4

const mockedAjvValidate = jest.fn().mockReturnValue(true);

jest.mock('ajv', () => {
    return jest.fn(() => ({
        compile: () => () => mockedAjvValidate()
    }))
});

Example 5

jest.mock('moment', () => () => ({ format: () => '30-12-2021' }));

Example 6

import { v4 as uuid } from 'uuid';

export interface IEvent {
    id?: string;
    eventType: string;
    data: any;
}

export interface IEventRepository {
    getEvent(id: string): IEvent | undefined;
    setEvent(event: IEvent): IEvent;
}

const createEvent = (event: IEvent): IEvent => ({ id: uuid(), ...event });

export class EventRedisRepository implements IEventRepository {

    constructor(private events: Array<IEvent> = []) { }

    getEvent(id: string): IEvent | undefined {
        return this.events.find(item => item.id === id);
    }
    setEvent(event: IEvent): IEvent {

        const newEvent: IEvent = createEvent(event);

        this.events.push(newEvent);

        return newEvent;
    }
}

export class EventCosmosDbRepository implements IEventRepository {

    constructor(private events: Array<IEvent> = []) { }

    getEvent(id: string): IEvent | undefined {
        return this.events.find(item => item.id === id);
    }
    setEvent(event: IEvent): IEvent {

        const newEvent: IEvent = createEvent(event);

        this.events.push(newEvent);

        return newEvent;
    }
}

import { Persister } from '../src';
import { EventRedisRepository, EventCosmosDbRepository, IEventRepository, IEvent } from './sample';

const mockedRedisGetEvent = jest.fn();

const mockedRedisSetEvent = jest.fn();

const mockedCosmosdbGetEvent = jest.fn();

const mockedCosmosdbSetEvent = jest.fn();

jest.mock('./sample', () => {
    return {
        EventRedisRepository: jest.fn(() => ({
            getEvent: () => mockedRedisGetEvent(),
            setEvent: () => mockedRedisSetEvent(),
        })),
        EventCosmosDbRepository: jest.fn(() => ({
            getEvent: () => mockedCosmosdbGetEvent(),
            setEvent: () => mockedCosmosdbSetEvent(),
        })),
    }
});

const eventRedisRepository = new EventRedisRepository();

const eventCosmosdbRepository = new EventCosmosDbRepository();

const module_name = `${Persister.name}`;

describe(`${module_name} Test`, () => {
    it('should call setEvent function in both persisters', () => {

        const eventPersister = new Persister<IEventRepository>([eventRedisRepository, eventCosmosdbRepository]);

        const eventId = '4e0c71bb-eedf-43dd-b9a1-911a7ed6d74f';
        const newEvent: IEvent = { id: eventId, eventType: 'Submission', data: {} };

        eventPersister.set('setEvent', op => op(newEvent));

        expect(mockedRedisSetEvent).toHaveBeenCalledTimes(1);

        expect(mockedCosmosdbSetEvent).toHaveBeenCalledTimes(1);

    });
});

Example 6 – updated and short version

import { Persister } from '../src';
import { EventRedisRepository, EventCosmosDbRepository, IEventRepository, IEvent } from './sample';
import { mocked } from 'jest-mock'

jest.mock('./sample');

const eventRedisRepository = new EventRedisRepository();

const eventCosmosdbRepository = new EventCosmosDbRepository();

const mockedEventRedisRepository = mocked(eventRedisRepository, true);

const mockedEventCosmosdbRepository = mocked(eventRedisRepository, true);

const module_name = `${Persister.name}`;

describe(`${module_name} Test`, () => {
    it('should call setEvent function in both persisters', () => {

        const eventPersister = new Persister<IEventRepository>([eventRedisRepository, eventCosmosdbRepository]);

        const eventId = '4e0c71bb-eedf-43dd-b9a1-911a7ed6d74f';
        const newEvent: IEvent = { id: eventId, eventType: 'Submission', data: {} };

        eventPersister.set('setEvent', op => op(newEvent));

        expect(mockedEventRedisRepository.setEvent).toHaveBeenCalledTimes(1);

        expect(mockedEventCosmosdbRepository.setEvent).toHaveBeenCalledTimes(1);

    });
});

How to create and run C# project

This post is just a reminder for me. So in order to find more details about dotnet CLI, follow the below link

https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet

$ dotnet new console -h

Console App (C#)
Author: Microsoft
Description: A project for creating a command-line application that can run on .NET on Windows, Linux and macOS

Usage:
  dotnet new console [options] [template options]

Options:
  -n, --name <name>       The name for the output being created. If no name is specified, the name of the output directory is used.
  -o, --output <output>   Location to place the generated output.
  --dry-run               Displays a summary of what would happen if the given command line were run if it would result in a template creation.
  --force                 Forces content to be generated even if it would change existing files.
  --no-update-check       Disables checking for the template package updates when instantiating a template.
  --project <project>     The project that should be used for context evaluation.
  -lang, --language <C#>  Specifies the template language to instantiate.
  --type <project>        Specifies the template type to instantiate.

Template options:
  -f, --framework <net5.0|net6.0|net7.0>  The target framework for the project.
                                          Type: choice
                                            net7.0  Target net7.0
                                            net6.0  Target net6.0
                                            net5.0  Target net5.0
                                          Default: net7.0
  --langVersion <langVersion>             Sets the LangVersion property in the created project file
                                          Type: text
  --no-restore                            If specified, skips the automatic restore of the project on create.
                                          Type: bool
                                          Default: false
  --use-program-main                      Whether to generate an explicit Program class and Main method instead of top-level statements.
                                          Type: bool
                                          Default: false

To see help for other template languages (F#, VB), use --language option:
   dotnet new console -h --language F#

Creating a C# Project

$ dotnet new --list

These templates matched your input: 

Template Name                                 Short Name          Language    Tags                            
--------------------------------------------  ------------------  ----------  --------------------------------
ASP.NET Core Empty                            web                 [C#],F#     Web/Empty                       
ASP.NET Core gRPC Service                     grpc                [C#]        Web/gRPC                        
ASP.NET Core Web API                          webapi              [C#],F#     Web/WebAPI                      
ASP.NET Core Web App                          webapp,razor        [C#]        Web/MVC/Razor Pages             
ASP.NET Core Web App (Model-View-Controller)  mvc                 [C#],F#     Web/MVC                         
ASP.NET Core with Angular                     angular             [C#]        Web/MVC/SPA                     
ASP.NET Core with React.js                    react               [C#]        Web/MVC/SPA                     
ASP.NET Core with React.js and Redux          reactredux          [C#]        Web/MVC/SPA                     
Blazor Server App                             blazorserver        [C#]        Web/Blazor                      
Blazor Server App Empty                       blazorserver-empty  [C#]        Web/Blazor/Empty                
Blazor WebAssembly App                        blazorwasm          [C#]        Web/Blazor/WebAssembly/PWA      
Blazor WebAssembly App Empty                  blazorwasm-empty    [C#]        Web/Blazor/WebAssembly/PWA/Empty
Class Library                                 classlib            [C#],F#,VB  Common/Library                  
Console App                                   console             [C#],F#,VB  Common/Console                  
dotnet gitignore file                         gitignore                       Config                          
Dotnet local tool manifest file               tool-manifest                   Config                          
EditorConfig file                             editorconfig                    Config                          
global.json file                              globaljson                      Config                          
MSBuild Directory.Build.props file            buildprops                      MSBuild/props                   
MSBuild Directory.Build.targets file          buildtargets                    MSBuild/props                   
MSTest Test Project                           mstest              [C#],F#,VB  Test/MSTest                     
MVC ViewImports                               viewimports         [C#]        Web/ASP.NET                     
MVC ViewStart                                 viewstart           [C#]        Web/ASP.NET                     
NuGet Config                                  nugetconfig                     Config                          
NUnit 3 Test Item                             nunit-test          [C#],F#,VB  Test/NUnit                      
NUnit 3 Test Project                          nunit               [C#],F#,VB  Test/NUnit                      
Protocol Buffer File                          proto                           Web/gRPC                        
Razor Class Library                           razorclasslib       [C#]        Web/Razor/Library               
Razor Component                               razorcomponent      [C#]        Web/ASP.NET                     
Razor Page                                    page                [C#]        Web/ASP.NET                     
Solution File                                 sln,solution                    Solution                        
Web Config                                    webconfig                       Config                          
Worker Service                                worker              [C#],F#     Common/Worker/Web               
xUnit Test Project                            xunit               [C#],F#,VB  Test/xUnit  
$ dotnet --list-sdks

5.0.408 [/Users/kenanhancer/.dotnet/sdk]
6.0.411 [/Users/kenanhancer/.dotnet/sdk]
7.0.305 [/Users/kenanhancer/.dotnet/sdk]

Creating a Console Project

Use any template short name after dotnet net and .NET SDK version after --framework option.

$ dotnet new console --framework net6.0 -o console-demo1

Creating a WebApi Project

$ dotnet new webapi --framework net6.0 -o webapi-todo-demo1

Specify .NET version in project folder

If you have multiple versions of the .NET Core SDK installed, the version that's used can be controlled using a global.json file. This file allows you to specify which version of the .NET Core SDK should be used.

$ dotnet new globaljson --sdk-version 6.0.411 --force

1. Creating a C# Console Project

-o or –output is location to place for new generated project.

$ dotnet new console --framework net6.0 --output enum_demo4

# OR

$ dotnet new console --framework net6.0 -o enum_demo4

# OR

$ dotnet new console --framework net6.0 --name enum_demo4
Folder Structure
Generated Project
Continue reading

How to compile and run Java Projects with java and javac commands

Compiling

-d is output directory for new generated class files.

How to compile single Java source file

javac -d ./target/classes src/main/java/com/extuni/enum_demo4/App.java

How to compile multiple Java source files

javac -d ./target/classes 
./src/main/java/com/extuni/enum_demo4/App.java 
./src/main/java/com/extuni/enum_demo4/Greeting.java 
./src/main/java/com/extuni/enum_demo4/Helper.java

How to compile multiple Java source files using wildcard

javac -d ./target/classes ./src/main/**/*.java

How to specify dependency jar file when compiling

Trying to compile ./src folder completely will throw exception due to junit.jar file dependency. So, it should be specified using -cp option which means –classpath as below.

javac -d ./target/classes -cp /Users/kenanhancer/.m2/repository/junit/junit/4.11/junit-4.11.jar ./src/**/*.java
Continue reading