Notice that addTodoV2
and addTodoV3
error for extra field WRONG_FIELD
, but addTodoV1
doesn't error for extra field in line 45.
Author: admin
TypeScript Creating Union Type from a Union Type
type TodoAction =
| { type: 'INIT' }
| { type: 'ADD_TODO', text: string }
| { type: 'REMOVE_TODO', id: string }
| { type: 'SET_COMPLETED', id: string };
type KeysOfUnion<T extends { type: any }> =
T extends { type: infer K } ? {} extends Omit<Extract<T, { type: K }>, 'type'> ? never : K : never;
function dispatch(actionType: KeysOfUnion<TodoAction>) { throw new Error('Not implemented') };
dispatch('ADD_TODO');
Continue reading TypeScript Separate Union Type Fields
My aim is to create a function which has two parameters. First one is union value of type
field in Action
and second parameter should force developer to use specific object in Action
.
For example, assume that we have this function function dispatch(actionType, payload){}
dispatch('SIGN_OUT', { type: 'SIGN_OUT', userName: ''
});
or
dispatch('SIGN_IN_FAILURE', { type: 'SIGN_IN_FAILURE', error: '' });
type Action =
| { type: 'INIT' }
| { type: 'SYNC' }
| { type: 'SIGN_UP', userName: string, password: string, attributeList: Array<any> }
| { type: 'SIGN_IN', userName: string, pasword: string }
| { type: 'SIGN_IN_SUCCESS', accessToken: string }
| { type: 'SIGN_IN_FAILURE', error: string }
| { type: 'SIGN_OUT', userName: string }
| { type: 'FORGOT_PASSWORD', userName: string }
| { type: 'FORGOT_PASSWORD_SUCCESS', verificationCode: string }
| { type: 'CHANGE_PASSWORD', userName: string, oldPassword: string, newPassword: string }
| { type: 'CONFIRM_REGISTRATION', userName: string, confirmationCode: string }
| { type: 'RESEND_CONFIRMATION_CODE', userName: string }
| { type: 'DELETE_USER', userName: string }
| { type: 'GET_SESSION', userName: string }
| { type: 'GET_SESSION_SUCCESS', session: string };
type TodoAction =
| { type: 'INIT' }
| { type: 'ADD_TODO', text: string }
| { type: 'REMOVE_TODO', id: string }
| { type: 'SET_COMPLETED', id: string };
Continue reading Azure Cosmos DB Emulator and Storage Emulator
Azurite emulator provides a free local environment for testing your Azure blob, queue storage, and table storage applications. Find more details in https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azurite?tabs=docker-hub
Cosmosdb emulator provides a local environment that emulates the Azure Cosmos DB service for development purposes. Using the Azure Cosmos DB Emulator, you can develop and test your application locally. You can develop applications using Azure Cosmos DB Emulator with the SQL, Cassandra, MongoDB, Gremlin/Graph, and Table API accounts. Currently the data explorer in the emulator fully supports viewing SQL data only; the data created using MongoDB, Gremlin/Graph and Cassandra client applications it is not viewable at this time.
Creating docker-compose.yml file
version: '3.4'
services:
cosmosdb:
container_name: cosmosdb
image: "mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator"
tty: true
restart: always
mem_limit: 3g
cpu_count: 2
environment:
- AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10
- AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true
- AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE=${HOST_IP}
ports:
- "8081:8081"
- "10251:10251"
- "10252:10252"
- "10253:10253"
- "10254:10254"
volumes:
- vol_cosmos:/data/db
azurite:
container_name: azurite
image: "mcr.microsoft.com/azure-storage/azurite"
restart: always
ports:
- "10000:10000"
- "10001:10001"
- "10002:10002"
volumes:
- vol_cosmos:/data
volumes:
vol_cosmos:
Continue reading TypeScript listen property value changes
Creating makeWatchedObject function with overloading
type PropEventSource<T> = {
on<K extends string & keyof T>(eventName: `${K}Changed`, callback: (newValue: T[K]) => void): void;
};
type ReturnType<T1> = T1 & PropEventSource<T1>;
function makeWatchedObject<T1>(obj1: T1): ReturnType<T1>
function makeWatchedObject<T1, T2>(obj1: T1, obj2: T2): ReturnType<T1 & T2>
function makeWatchedObject<T1, T2, T3>(obj1: T1, obj2: T2, obj3: T3): ReturnType<T1 & T2 & T3>
function makeWatchedObject<T1, T2, T3>(obj1: T1, obj2?: T2, obj3?: T3): any {
const events = new Map<string, (a: any) => void>();
const on_: PropEventSource<T1 & T2 & T3> = {
on(eventName: string, callback: (newValue: any) => void): void {
events.set(eventName, callback);
}
}
const obj = { ...obj1, ...obj2, ...obj3, ...on_ };
const proxyObj = new Proxy(obj, {
set: function (target, property, value, receiver) {
const event = events.get(`${property as string}Changed`);
if (event) {
event(value);
return true;
}
return Reflect.set(target, property, value, receiver);
}
});
return proxyObj;
}
Usage
const personInfo = { id: 1, firstName: 'kenan', lastName: 'hancer', age: 36 };
const personAddress = { country: 'UK', city: 'London' };
const personContact = { email: 'kh@kh.com', phone: '077111-33-33' };
let person = makeWatchedObject(personInfo, personAddress, personContact);
// works! 'newName' is typed as 'string'
person.on("firstNameChanged", (newName: string) => {
console.log(`new name is ${newName.toUpperCase()}`);
});
// works! 'newAge' is typed as 'number'
person.on("ageChanged", (newAge: number) => {
if (newAge < 0) {
console.log("warning! negative age");
}
});
person.age = 34;
TypeScript Function Conditional Type Good Usage
Example 1
type MessageOf<T> = T extends { message: infer MessageType } ? MessageType : never;
const getMessage = <T extends { message: any }>(obj: T): MessageOf<T> => obj.message;
const sms = { phone: '07733838', message: ['Hello World', 'Merhaba Dunya'] };
const smsMessage = getMessage(sms); // string[]
const email = { from: 'kh@kh.com', to: 'kkkk@kkkk.com', message: 'Hello World' };
const emailMessage = getMessage(email); // string
Example 1.1
Notice that line 3 in below code, T extends { message: unknown }
message field data type is unknown so returning value from function should be casted to any like obj.message as any
type MessageOf<T> = T extends { message: infer MessageType } ? MessageType : never;
const getMessage = <T extends { message: unknown }>(obj: T): MessageOf<T> => obj.message as any;
const sms = { phone: '07733838', message: ['Hello World', 'Merhaba Dunya'] };
const smsMessage = getMessage(sms); // string[]
const email = { from: 'kh@kh.com', to: 'kkkk@kkkk.com', message: 'Hello World' };
const emailMessage = getMessage(email); // string
TypeScript Inferring from Function
TypeScript Inferring in Conditional Types
Example 1
Continue readingTypeScript 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