npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@gargoylesoft/obj-for-dto

v1.3.9

Published

Create an object and DTO for network retrieved JSON

Downloads

36

Readme

Object for DTO

This is a schematic to auto-generate your model file based on the defined DTO type.

Installation

ng add @gargoylesoft/obj-for-dto

The schematic will get installed as well as creating a file at src/app/has-value.ts which implements a type guard.

Usage

The first parameter to the schematic should be the class name to create, and the second is a comma separated list of properties to include in the model. Property names will default to a string type if not specified. You specify the type of the property by appending a : and a type name.

If the property is an array, you can add [] after the type name.

If the property is optional, you can add a ? character after the type name.

The following shortcut types are available:

  • s -> string
  • n -> number
  • b -> boolean
  • d -> Date

Assumptions

  1. The generated class does not use undefined values. Non-present optional values get set to null
  2. Arrays always have a value. Non-present optional arrays are set to an empty array.
  3. Empty strings that are nullable and not present are set to null.
  4. Only call the constructor in your unit tests.

Usage in Angular

Use the fromJson static method in your angular service:

@Injectable({
    providedIn: 'root'
})
export class EmployeeService {
    readonly #http = inject(HttpClient)
    
    getEmployee(id: string): Observable<Employee | undefined> {
        return this.#http.get<EmployeeDTO>('...').pipe(
            map(Employee.fromJson)
        )
    }
    
    getAllEmployees(): Observable<Employee[] | undefined> {
        return this.#http.get<EmployeeDTO[]>('...').pipe(
            map(x => x.map(Employee.fromJson).filter(hasValue))
        )
    }
}

Notice in the getAllEmployees example the array of entries is passed to the fromJson method, which will return undefined if parsing failed. You then pass that to filter(hasValue) to only include validated objects in the result set.

Depending on your workflow, you can either ignore bad input, as shown here, or do something more intelligent to throw an error if any results failed to parse.

Example

Create a simple Employee model:

ng g @gargoylesoft/obj-for-dto:obj-for-dto Employee name,email,wwid:n,active:b

results in the following file being created:

import {hasValue} from '../has-value'

export type IEmployee = {
   active: boolean
   email: string
   name: string
   wwid: number
}

export type EmployeeDTO = Partial<IEmployee>

export class Employee implements IEmployee {
    constructor(
      public readonly active: boolean,
      public readonly email: string,
      public readonly name: string,
      public readonly wwid: number
    ) {
    }

    static fromJson(json: EmployeeDTO | null | undefined): Employee | undefined {
        if (!(json && hasValue(json.active) && json.email && json.name && hasValue(json.wwid)))
            return undefined

        return new Employee(json.active, json.email, json.name, json.wwid)
    }
}

Showing all possibilities by using a name of Example and a property list of requiredString,optionalString:s?,requiredStringArray:s[],optionalStringArray:s[]?,requiredDate:d,optionalDate:d?,requiredDateArray:d[],optionalDateArray:d[]?,requiredNumber:n,optionalNumber:n?,requiredNumberArray:n[],optionalNumberArray:n[]?,requiredBoolean:b,optionalBoolean:b?,requiredBooleanArray:b[],optionalBooleanArray:b[]?,requiredEmployee:Employee,optionalEmployee:Employee?,requiredEmployeeArray:Employee[],optionalEmployeeArray:Employee[]?

results in the following file being created:

import {Employee, EmployeeDTO, IEmployee} from './employee'
import {hasValue} from '../has-value'

export type IExample = {
    optionalBoolean: boolean | null
    optionalBooleanArray: boolean[]
    optionalDate: Date | null
    optionalDateArray: Date[]
    optionalEmployee: IEmployee | null
    optionalEmployeeArray: IEmployee[]
    optionalNumber: number | null
    optionalNumberArray: number[]
    optionalString: string | null
    optionalStringArray: string[]
    requiredBoolean: boolean
    requiredBooleanArray: boolean[]
    requiredDate: Date
    requiredDateArray: Date[]
    requiredEmployee: IEmployee
    requiredEmployeeArray: IEmployee[]
    requiredNumber: number
    requiredNumberArray: number[]
    requiredString: string
    requiredStringArray: string[]
}

export type ExampleDTO = Omit<Partial<IExample>, 'optionalEmployee' | 'optionalEmployeeArray' | 'requiredEmployee' | 'requiredEmployeeArray'> & {
    optionalEmployee?: EmployeeDTO | null
    optionalEmployeeArray?: EmployeeDTO[] | null
    requiredEmployee?: EmployeeDTO | null
    requiredEmployeeArray?: EmployeeDTO[] | null
}

export class Example implements IExample {
    constructor(
        public readonly optionalBoolean: boolean | null,
        public readonly optionalBooleanArray: boolean[],
        public readonly optionalDate: Date | null,
        public readonly optionalDateArray: Date[],
        public readonly optionalEmployee: Employee | null,
        public readonly optionalEmployeeArray: Employee[],
        public readonly optionalNumber: number | null,
        public readonly optionalNumberArray: number[],
        public readonly optionalString: string | null,
        public readonly optionalStringArray: string[],
        public readonly requiredBoolean: boolean,
        public readonly requiredBooleanArray: boolean[],
        public readonly requiredDate: Date,
        public readonly requiredDateArray: Date[],
        public readonly requiredEmployee: Employee,
        public readonly requiredEmployeeArray: Employee[],
        public readonly requiredNumber: number,
        public readonly requiredNumberArray: number[],
        public readonly requiredString: string,
        public readonly requiredStringArray: string[]
    ) {
    }

    static fromJson(json: ExampleDTO | null | undefined): Example | undefined {
        if (!(json && hasValue(json.requiredBoolean) && Array.isArray(json.requiredBooleanArray) && json.requiredDate && Array.isArray(json.requiredDateArray) && Array.isArray(json.requiredEmployeeArray) && hasValue(json.requiredNumber) && Array.isArray(json.requiredNumberArray) && json.requiredString && Array.isArray(json.requiredStringArray)))
            return undefined

        let optionalBooleanArray: boolean[] = []
        if (json.optionalBooleanArray) {
            if (!Array.isArray(json.optionalBooleanArray))
                return undefined

            optionalBooleanArray = json.optionalBooleanArray.filter(hasValue)
            if (optionalBooleanArray.length !== json.optionalBooleanArray.length)
                return undefined
        }

        const optionalDate = json.optionalDate ? new Date(json.optionalDate) : null
        if (optionalDate && !isFinite(optionalDate.getTime()))
            return undefined

        let optionalDateArray: Date[] = []
        if (json.optionalDateArray) {
            if (!Array.isArray(json.optionalDateArray))
                return undefined

            optionalDateArray = json.optionalDateArray?.map(x => new Date(x)).filter(x => isFinite(x.getTime()))
            if (optionalDateArray.length !== json.optionalDateArray.length)
                return undefined
        }

        const optionalEmployee = Employee.fromJson(json.optionalEmployee) ?? null

        const optionalEmployeeArray = json.optionalEmployeeArray.map(Employee.fromJson).filter(hasValue) ?? []

        let optionalNumberArray: number[] = []
        if (json.optionalNumberArray) {
            if (!Array.isArray(json.optionalNumberArray))
                return undefined

            optionalNumberArray = json.optionalNumberArray.filter(Number.isFinite)
            if (optionalNumberArray.length !== json.optionalNumberArray.length)
                return undefined
        }

        let optionalStringArray: string[] = []
        if (json.optionalStringArray) {
            if (!Array.isArray(json.optionalStringArray))
                return undefined

            optionalStringArray = json.optionalStringArray.filter(hasValue)
            if (optionalStringArray.length !== json.optionalStringArray.length)
                return undefined
        }

        let requiredBooleanArray: boolean[] = []
        if (!Array.isArray(json.requiredBooleanArray))
            return undefined

        requiredBooleanArray = json.requiredBooleanArray.filter(hasValue)
        if (requiredBooleanArray.length !== json.requiredBooleanArray.length)
            return undefined

        const requiredDate = new Date(json.requiredDate)
        if (!isFinite(requiredDate.getTime()))
            return undefined

        let requiredDateArray: Date[] = []
        if (!Array.isArray(json.requiredDateArray))
            return undefined

        requiredDateArray = json.requiredDateArray?.map(x => new Date(x)).filter(x => isFinite(x.getTime()))
        if (requiredDateArray.length !== json.requiredDateArray.length)
            return undefined

        const requiredEmployee = Employee.fromJson(json.requiredEmployee)
        if (!requiredEmployee)
            return undefined

        const requiredEmployeeArray = json.requiredEmployeeArray.map(Employee.fromJson).filter(hasValue)
        if (!requiredEmployeeArray)
            return undefined

        let requiredNumberArray: number[] = []
        if (!Array.isArray(json.requiredNumberArray))
            return undefined

        requiredNumberArray = json.requiredNumberArray.filter(Number.isFinite)
        if (requiredNumberArray.length !== json.requiredNumberArray.length)
            return undefined

        let requiredStringArray: string[] = []
        if (!Array.isArray(json.requiredStringArray))
            return undefined

        requiredStringArray = json.requiredStringArray.filter(hasValue)
        if (requiredStringArray.length !== json.requiredStringArray.length)
            return undefined

        return new Example(hasValue(json.optionalBoolean) ? json.optionalBoolean : null, optionalBooleanArray, optionalDate, optionalDateArray, optionalEmployee, optionalEmployeeArray, hasValue(json.optionalNumber) ? json.optionalNumber : null, optionalNumberArray, json.optionalString || null, optionalStringArray, json.requiredBoolean, requiredBooleanArray, requiredDate, requiredDateArray, requiredEmployee, requiredEmployeeArray, json.requiredNumber, requiredNumberArray, json.requiredString, requiredStringArray)
    }
}