TypeScript transformer for creating object representation of deeply nested types.
The library provides a custom typescript transformer that creates object representation of provided Type.
To transform a type use objectifyType
from the ts-objectify-type
module:
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
//...
}
const obj = objectifyType<ExampleType>();
Returned object is of type objectified.TypeRepresentation
, which is alias for objectified.Property[]
.
objectified
namespace provides all types for the object returned by the objectifyType
function, and can be also imported from the ts-objectify-type
.
Check examples for more information.
Install ts-objectify-type
with npm:
npm install ts-objectify-type --save-dev
or yarn:
yarn add ts-objectify-type -D
TypeScript >= 2.4.1
TypeScript provides limited support for using custom transformers, but it doesn't have built-in, easy-to-use options for this purpose. However, there are alternative solutions available.
The easiest solution is to use a community-driven library called ts-patch, which offers a way to overcome this limitation and utilize custom transformers with TypeScript projects. The package is build based on ttypescript (for more info check next section).
- Install
ts-patch
as a dev-dependency with npm:
npm install ts-patch --save-dev
or yarn:
yarn add ts-patch -D
- Add prepare script (keeps patch persisted after npm install)
// package.json
{
"scripts": {
"prepare": "ts-patch install -s"
}
}
- In
tsconfig.json
set a path to the transformer in thecompilerOptions
plugins
array:
// tsconfig.json
{
"compilerOptions": {
"plugins": [
{ "transform": "ts-objectify-type/transformer" }
]
}
}
TTypescript (Transformer TypeScript) solves the problem by patching on the fly the compile module to use transformers from tsconfig.json
.
Instead of tsc
and tsserver
, use ttsc
and ttsserver
wrappers.
These wrappers try to use locally installed typescript first.
ttypescript
is also compatible with Webpack and Rollup (check ttypescript repo for more info)
- Install
ttypescript
as a dev-dependency with npm:
npm install ttypescript --save-dev
or yarn:
yarn add ttypescript -D
- In
tsconfig.json
set a path to the transformer in thecompilerOptions
plugins
array:
// tsconfig.json
{
"compilerOptions": {
"plugins": [
{ "transform": "ts-objectify-type/transformer" }
]
}
}
- To build project use
ttsc
instead oftsc
. All arguments work the same way
ttsc
- ts-loader (Webpack)
- awesome-typescript-loader (Webpack)
- rollup-plugin-typescript2 (Rollup)
There are several type groups, each represented by an interface. The interfaces are designed to provide the most information from the corresponding type.
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
prop: string;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
"key": "prop",
"required": true,
"type": "string"
}
]
There are 3 base properties that every "objectified" property has:
key
string | number | symbol - Name of the propertyrequired
boolean - Whether property is marked as requiredtype
objectified.TypeValue (string) - Type of the property. Main idea behind it is to represent whattypeof
keyword would return when used on the type, but with few extra. You can check all of them in examples section.
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
requiredProp: string;
optionalProp?: string;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: 'requiredProp',
required: true,
type: 'string'
},
{
key: 'optionalProp',
required: false,
type: 'string'
}
];
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
primitiveVoid: void;
primitiveNever: never;
primitiveNumber: number;
primitiveString: string;
primitiveBoolean: boolean;
primitiveUndefined: undefined;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: 'primitiveVoid',
required: true,
type: 'void'
},
{
key: 'primitiveNever',
required: true,
type: 'never'
},
{
key: 'primitiveNumber',
required: true,
type: 'number'
},
{
key: 'primitiveString',
required: true,
type: 'string'
},
{
key: 'primitiveBoolean',
required: true,
type: 'boolean'
},
{
key: 'primitiveUndefined',
required: true,
type: 'undefined'
}
];
Generated properties type: objectified.PrimitiveType
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
literalObj: {
prop1: string;
prop2: number;
};
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "literalObj",
required: true,
type: "object",
objectType: "literal",
props: [
{
key: "prop1",
required: true,
type: "string"
},
{
key: "prop2",
required: true,
type: "number"
}
]
}
];
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
nullProp: null;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "nullProp",
required: true,
type: "object",
objectType: "null",
}
];
null
is technically primitive, but whentypeof
is used, it returns"object"
.
So in generated objecttype="object"
andobjectType="null"
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
simpleArray: string[];
classArray: Array<string>;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "simpleArray",
required: true,
type: "object",
objectType: "array",
arrayType: {
type: "string"
}
},
{
key: "classArray",
required: true,
type: "object",
objectType: "array",
arrayType: {
type: "string"
}
}
];
Generated properties type: objectified.ArrayType
arrayType
(objectified.Type) - represents type of the array
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
simpleTuple: [string, number?];
namedTuple: [
one: string,
two?: number
];
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "simpleTuple",
required: true,
type: "object",
objectType: "tuple",
tupleType: [
{
key: 0,
required: true,
type: "string"
},
{
key: 1,
required: false,
type: "number"
}
]
},
{
key: "namedTuple",
required: true,
type: "object",
objectType: "tuple",
tupleType: [
{
key: "one",
required: false,
type: "string"
},
{
key: "two",
required: true,
type: "number"
}
]
}
];
Generated properties type: objectified.TupleType
tupleType
objectified.Property[] - an array representation of tuple individual types
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
voidFn: () => void;
argsFn: (arg1: string, arg2: number) => string;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "voidFn",
required: true,
type: "function",
arguments: [],
returnType: {
type: "void"
}
},
{
key: "argsFn",
required: true,
type: "function",
arguments: [
{
key: "arg1",
required: true,
type: "string"
},
{
key: "arg2",
required: true,
type: "number"
}
],
returnType: {
type: "string"
}
}
];
Generated property type: objectified.FunctionType
arguments
objectified.Property[] - an array of function arguments representationsreturnType
objectified.Type - function return type representation
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
primitivesUnion: string | number;
objsUnion: { a: string } | { b: number };
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "primitivesUnion",
required: true,
type: "union",
unionOf: [
{
type: "string"
},
{
type: "number"
}
]
},
{
key: "objsUnion",
required: true,
type: "union",
unionOf: [
{
type: "object",
objectType: "literal",
props: [
{
key: "a",
required: true,
type: "string"
}
]
},
{
type: "object",
objectType: "literal",
props: [
{
key: "b",
required: true,
type: "number"
}
]
}
]
}
];
Generated properties type: objectified.UnionType
unionOf
objectified.Type[] - type representation of individual union members
import { objectifyType } from 'ts-objectify-type';
interface ExampleType {
primitivesIntersection: string & number; // = never
objsIntersection: { a: string } & { b: number };
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "primitivesIntersection",
required: true,
type: "never"
},
{
key: "objsIntersection",
required: true,
type: "intersection",
intersectionOf: [
{
type: "object",
objectType: "literal",
props: [
{
key: "a",
required: true,
type: "string"
}
]
},
{
type: "object",
objectType: "literal",
props: [
{
key: "b",
required: true,
type: "number"
}
]
}
]
}
];
Generated properties type: objectified.IntersectionType
intersectionOf
objectified.Type[] - type representation of individual intersection members
Note that
primitivesIntersection
is set asstring & number
but they have no common properties and typescript treats it as anever
and same is returned when objectified.
import { objectifyType } from 'ts-objectify-type';
export interface SimpleInterface {
prop: string;
}
interface ExampleType {
simpleRef: SimpleInterface;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "simpleRef",
required: true,
type: "object",
objectType: "reference",
referenceName: "SimpleInterface",
props: [
{
key: "prop",
required: true,
type: "string"
}
]
}
];
Generated property type: objectified.ReferenceType
referenceName
string - name of the referenced typeprops
objectified.Type[] - same as in literal object, the nested properties are represented.
import { objectifyType } from 'ts-objectify-type';
export interface InterfaceWithGeneric<T> {
prop: T;
}
interface ExampleType {
genericRef: InterfaceWithGeneric<string>;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "refWithGeneric",
required: true,
type: "object",
objectType: "reference",
referenceName: "InterfaceWithGeneric",
typeArguments: [
{
type: "string"
}
],
props: [
{
key: "prop",
required: true,
type: "string"
}
]
}
];
Generated property type: objectified.ReferenceType
typeArguments
objectified.Type[] - an array of generic parameters representations
import { objectifyType } from 'ts-objectify-type';
export interface InterfaceCircular {
selfRef: InterfaceCircular;
}
interface ExampleType {
circularRef: InterfaceCircular;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "refCircular",
required: true,
type: "object",
objectType: "reference",
referenceName: "InterfaceCircular",
props: [
{
key: "selfRef",
required: true,
type: "object",
objectType: "reference",
referenceName: "InterfaceCircular",
isCircular: true
}
]
}
];
Generated properties type: objectified.ReferenceType
,
isCircular
boolean - indicates whether the property references a type that has already been referenced earlier in the same object
import { objectifyType } from 'ts-objectify-type';
export interface SimpleInterface {
prop: string;
}
type AliasType = SimpleInterface;
interface ExampleType {
aliasRef: AliasType;
}
const obj = objectifyType<ExampleType>();
// Generated result:
const obj = [
{
key: "aliasRef",
required: true,
type: "object",
objectType: "reference",
referenceName: "SimpleInterface",
props: [
{
key: "prop",
required: true,
type: "string"
}
]
}
];
Generated properties type: objectified.ReferenceType
,
Note that even though the type of
aliasRef
is set asAliasType
, thereferenceName
is directlySimpleInterface
The following utility functions are available in the objectified
namespace to narrow down objectified.Type
.
All functions take one argument of objectified.Type
type.
isProperty(type)
- haskey
andrequired
propertiesisRequired(type)
-required
istrue
isOptional(type)
-required
isfalse
isString(type)
- whether is stringisNumber(type)
- whether is numberisBoolean(type)
- whether is booleanisUndefined(type)
- whether is undefinedisNull(type)
- whether is null
isFunction(type)
- whether is function
isUnion(type)
- whether is unionisIntersection(type)
- whether is intersection
isArray(type)
- whether is arrayisTuple(type)
- whether is tupleisArrayOrTuple(type)
- whether is array or tuple
isLiteralObject(type)
- whether is literal objectisReference(type)
- whether is referenceisCircularReference(type)
- whether is circular referencehasProps(type)
- whether it hasprops
property (meaning reference or literal object)isUnknownObject(type)
- unknown object represents error or unsupported type (please report a bug when encountered)
isVoid(type)
- whether is voidisNever(type)
- whether is neverisGenericParameter(type)
- whether is generic type parameter
isNotNullPrimitive(type)
- string, number, boolean or undefinedisPrimitive(type)
- "Not Null Primitive", or nullisNotObject(type)
- "Not Null Primitive", void or neverisNotNullObject(type)
- literal object, array, tuple reference, unknown objectisObject(type)
- Not Null Object or null