Skip to main content

Emi string data type

Given the following example:

name: MyStringClass
fields:
- name: stringWithDefault
default: With default value
type: string
- name: emptyString
type: string

string and string? types will be converted into the javascript counter part with a difference that ? allows the null value, and by default is undefined. As a general pattern the field private value (#field) would be created, and based on that, there will be getters and setters.

First let's take a look on the string, and see how it would prevent the crashes by generating the typesafe code:

/**
* The base class definition for myStringClassDto
**/
export class MyStringClassDto {
/**
*
* @type {string}
**/
#stringWithDefault: string = "With default value";
/**
*
* @returns {string}
**/
get stringWithDefault() {
return this.#stringWithDefault;
}
/**
*
* @type {string}
**/
set stringWithDefault(value: string) {
this.#stringWithDefault = String(value);
}
setStringWithDefault(value: string) {
this.stringWithDefault = value;
return this;
}
/**
*
* @type {string}
**/
#emptyString: string = "";
/**
*
* @returns {string}
**/
get emptyString() {
return this.#emptyString;
}
/**
*
* @type {string}
**/
set emptyString(value: string) {
this.#emptyString = String(value);
}
setEmptyString(value: string) {
this.emptyString = value;
return this;
}
constructor(data: unknown = undefined) {
if (data === null || data === undefined) {
return;
}
if (typeof data === "string") {
this.applyFromObject(JSON.parse(data));
} else if (this.#isJsonAppliable(data)) {
this.applyFromObject(data);
} else {
throw new Error(
"Instance cannot be created on an unknown value, check the content being passed. got: " +
typeof data,
);
}
}
#isJsonAppliable(obj: unknown) {
const g = globalThis as unknown as { Buffer: any; Blob: any };
const isBuffer =
typeof g.Buffer !== "undefined" &&
typeof g.Buffer.isBuffer === "function" &&
g.Buffer.isBuffer(obj);
const isBlob = typeof g.Blob !== "undefined" && obj instanceof g.Blob;
return (
obj &&
typeof obj === "object" &&
!Array.isArray(obj) &&
!isBuffer &&
!(obj instanceof ArrayBuffer) &&
!isBlob
);
}
/**
* casts the fields of a javascript object into the class properties one by one
**/
applyFromObject(data = {}) {
const d = data as Partial<MyStringClassDto>;
if (d.stringWithDefault !== undefined) {
this.stringWithDefault = d.stringWithDefault;
}
if (d.emptyString !== undefined) {
this.emptyString = d.emptyString;
}
}
/**
* Special toJSON override, since the field are private,
* Json stringify won't see them unless we mention it explicitly.
**/
toJSON() {
return {
stringWithDefault: this.#stringWithDefault,
emptyString: this.#emptyString,
};
}
toString() {
return JSON.stringify(this);
}
static get Fields() {
return {
stringWithDefault: "stringWithDefault",
emptyString: "emptyString",
};
}
/**
* Creates an instance of MyStringClassDto, and possibleDtoObject
* needs to satisfy the type requirement fully, otherwise typescript compile would
* be complaining.
**/
static from(possibleDtoObject: MyStringClassDtoType) {
return new MyStringClassDto(possibleDtoObject);
}
/**
* Creates an instance of MyStringClassDto, and partialDtoObject
* needs to satisfy the type, but partially, and rest of the content would
* be constructed according to data types and nullability.
**/
static with(partialDtoObject: PartialDeep<MyStringClassDtoType>) {
return new MyStringClassDto(partialDtoObject);
}
copyWith(
partial: PartialDeep<MyStringClassDtoType>,
): InstanceType<typeof MyStringClassDto> {
return new MyStringClassDto({ ...this.toJSON(), ...partial });
}
clone(): InstanceType<typeof MyStringClassDto> {
return new MyStringClassDto(this.toJSON());
}
}
export abstract class MyStringClassDtoFactory {
abstract create(data: unknown): MyStringClassDto;
}
type PartialDeep<T> = {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<PartialDeep<U>>
: T[P] extends object
? PartialDeep<T[P]>
: T[P];
};
/**
* The base type definition for myStringClassDto
**/
export type MyStringClassDtoType = {
/**
*
* @type {string}
**/
stringWithDefault: string;
/**
*
* @type {string}
**/
emptyString: string;
};
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace MyStringClassDtoType {}

Given the following example:

name: MyStringClass
fields:
- name: nullableStringWithDefault
default: With default value
type: string?
- name: nullableWithoutDefault
type: string?

In nullable scenario, the field is initialised with 'undefined' and allows null value as well. If default provided, the default value will be placed.

/**
* The base class definition for myStringClassDto
**/
export class MyStringClassDto {
/**
*
* @type {string}
**/
#nullableStringWithDefault?: string | null = "With default value";
/**
*
* @returns {string}
**/
get nullableStringWithDefault() {
return this.#nullableStringWithDefault;
}
/**
*
* @type {string}
**/
set nullableStringWithDefault(value: string | null | undefined) {
const correctType =
typeof value === "string" || value === undefined || value === null;
this.#nullableStringWithDefault = correctType ? value : String(value);
}
setNullableStringWithDefault(value: string | null | undefined) {
this.nullableStringWithDefault = value;
return this;
}
/**
*
* @type {string}
**/
#nullableWithoutDefault?: string | null = undefined;
/**
*
* @returns {string}
**/
get nullableWithoutDefault() {
return this.#nullableWithoutDefault;
}
/**
*
* @type {string}
**/
set nullableWithoutDefault(value: string | null | undefined) {
const correctType =
typeof value === "string" || value === undefined || value === null;
this.#nullableWithoutDefault = correctType ? value : String(value);
}
setNullableWithoutDefault(value: string | null | undefined) {
this.nullableWithoutDefault = value;
return this;
}
constructor(data: unknown = undefined) {
if (data === null || data === undefined) {
return;
}
if (typeof data === "string") {
this.applyFromObject(JSON.parse(data));
} else if (this.#isJsonAppliable(data)) {
this.applyFromObject(data);
} else {
throw new Error(
"Instance cannot be created on an unknown value, check the content being passed. got: " +
typeof data,
);
}
}
#isJsonAppliable(obj: unknown) {
const g = globalThis as unknown as { Buffer: any; Blob: any };
const isBuffer =
typeof g.Buffer !== "undefined" &&
typeof g.Buffer.isBuffer === "function" &&
g.Buffer.isBuffer(obj);
const isBlob = typeof g.Blob !== "undefined" && obj instanceof g.Blob;
return (
obj &&
typeof obj === "object" &&
!Array.isArray(obj) &&
!isBuffer &&
!(obj instanceof ArrayBuffer) &&
!isBlob
);
}
/**
* casts the fields of a javascript object into the class properties one by one
**/
applyFromObject(data = {}) {
const d = data as Partial<MyStringClassDto>;
if (d.nullableStringWithDefault !== undefined) {
this.nullableStringWithDefault = d.nullableStringWithDefault;
}
if (d.nullableWithoutDefault !== undefined) {
this.nullableWithoutDefault = d.nullableWithoutDefault;
}
}
/**
* Special toJSON override, since the field are private,
* Json stringify won't see them unless we mention it explicitly.
**/
toJSON() {
return {
nullableStringWithDefault: this.#nullableStringWithDefault,
nullableWithoutDefault: this.#nullableWithoutDefault,
};
}
toString() {
return JSON.stringify(this);
}
static get Fields() {
return {
nullableStringWithDefault: "nullableStringWithDefault",
nullableWithoutDefault: "nullableWithoutDefault",
};
}
/**
* Creates an instance of MyStringClassDto, and possibleDtoObject
* needs to satisfy the type requirement fully, otherwise typescript compile would
* be complaining.
**/
static from(possibleDtoObject: MyStringClassDtoType) {
return new MyStringClassDto(possibleDtoObject);
}
/**
* Creates an instance of MyStringClassDto, and partialDtoObject
* needs to satisfy the type, but partially, and rest of the content would
* be constructed according to data types and nullability.
**/
static with(partialDtoObject: PartialDeep<MyStringClassDtoType>) {
return new MyStringClassDto(partialDtoObject);
}
copyWith(
partial: PartialDeep<MyStringClassDtoType>,
): InstanceType<typeof MyStringClassDto> {
return new MyStringClassDto({ ...this.toJSON(), ...partial });
}
clone(): InstanceType<typeof MyStringClassDto> {
return new MyStringClassDto(this.toJSON());
}
}
export abstract class MyStringClassDtoFactory {
abstract create(data: unknown): MyStringClassDto;
}
type PartialDeep<T> = {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<PartialDeep<U>>
: T[P] extends object
? PartialDeep<T[P]>
: T[P];
};
/**
* The base type definition for myStringClassDto
**/
export type MyStringClassDtoType = {
/**
*
* @type {string}
**/
nullableStringWithDefault?: string;
/**
*
* @type {string}
**/
nullableWithoutDefault?: string;
};
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace MyStringClassDtoType {}