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 🙏

© 2024 – Pkg Stats / Ryan Hefner

core-types

v3.1.0

Published

Generic type declarations for e.g. TypeScript, GraphQL and JSON Schema

Downloads

82,602

Readme

npm version downloads build status coverage status Node.JS version

core-types

This package provides TypeScript types describing core types useful in TypeScript, JavaScript, JSON, JSON Schema etc. It also contains functions for simplifying unnecessarily complex types, as well helper utilities for other packages converting to/from core-types and another type system.

Using core-types, e.g. implementing conversions to other type systems is easy, since core-types is relatively small and well defined.

  • See use cases and other packages using this package
  • Usage
  • Specification of the types in this package are:
    • any (any of the below types)
    • null
    • boolean (true, false)
    • string
    • number and integer; distinguished in JSON Schema, equivalent in TypeScript
    • object; key-value of core types where the key is a string
    • array; list of arbitrary length of a specific core type
    • tuple; list of specific length with distinguished core types in each position
    • ref a reference to a named type
    • unions and intersections of the above

The above describes JSON completely, and is a lowest common denominator for describing types useful for JSON, JSON Schema and TypeScript. Think of it as an extremely simplified version of JSON Schema.

See

This package is used by:

Versions

Since 3.0 this package is pure ESM and requires Node 14.13.1 or later.

Usage

To create a core-types type, just cast it to NodeType.

import type { NodeType } from 'core-types'

const myStringType: NodeType = { type: 'string' };

For more information on the specific types, see the Specification.

simplify

The function simplify can take a type, or an array of types, and returns simplified type definitions.

Examples of simpifications performed:

  • An empty and or or will often be removed.
  • A union (e.g. of any and string), except for usages const and enum, can be simplified as just any.
  • An intersection of any and string can be simplified to string.
  • An or containing child ors, will be flattened to the parent or.
  • and more...

The simplify function is type-wise lossless, but can remove annotations (e.g. descriptions). It is however usually recommended to perform a simplification after a type has been converted to core-types before converting to another type system.

import { simplify } from 'core-types'

const simplified = simplify( myType );

simplify( {
	type: 'or',
	or: [
		{ type: 'or', or: [ { type: 'string' } ] },
		{ type: 'any', const: 'foo' }
	]
} ); // { type: 'string', const: 'foo' }

validate

The validate function validates that a NodeType type tree is valid.

It ensures e.g.

  • Non-negative integer minItems
  • Non-mismatching enums and const if both are specified.
import { validate } from 'core-types'

validate( myType ); // Throws error if not valid

traverse

The traverse function traverses a type tree and calls a callback function for every node it finds.

The callback function gets an object as argument on the following form:

interface TraverseCallbackArgument
{
	node: NodeType;
	rootNode: NodeType;
	path: Array< string | number >;
	parentProperty?: string;
	parentNode?: NodeType;
	index?: string | number;
	required?: boolean;
}
import { traverse } from 'core-types'

traverse( rootNode, ( { node } ) => {
	if ( !node.title )
		node.title = "This is a dummy title";
} );

some

The some function is similar to traverse but the callback can return a boolean. If the callback returns true, some returns true, otherwise false.

This is useful to quickly find if a node satisifes a certain criteria, and is similar to Array.prototype.some.

import { some } from 'core-types'

const hasRefNode = some( rootNode, ( { node: { type } } ) => type === 'ref' );

helpers

When implementing conversions to and from core-types, the following helper functions may come in handy:

  • ensureArray converts values to arrays of such values, or returns arrays as-is. null and undefined become empty array
  • isPrimitiveType returns true for primitive NodeTypes
  • hasConstEnum returns true for NodeTypes which has (or can have) const and enum properties.
  • isEqual deep-equal comparison (of JSON compatible non-recursive types)
  • intersection returns an array of values found in both of two arrays. Handles primitives as well as arrays and objects (uses isEqual)
  • union returns an array of unique values from two arrays. Handles primitives as well as arrays and objects (uses isEqual)
  • isNonNullable
  • isCoreTypesError
  • decorateErrorMeta
  • decorateError
  • getPositionOffset
  • mergeLocations

Annotations

  • mergeAnnotations
  • extractAnnotations
  • stringifyAnnotations
  • stripAnnotations
  • stringify

Conversion

When converting, a conversion package is recommended to return a ConversionResult<T>, i.e. the data as property data in an object which also contains information about the conversion:

interface ConversionResult< T = string >
{
	data: T;
	convertedTypes: Array< string >;
	notConvertedTypes: Array< string >;
}

Specification

The main type is called NodeType and is a union of the specific types. A NodeType always has a type property of the type Types. The Types is defined as:

type Types =
	| 'any'
	| 'null'
	| 'boolean'
	| 'string'
	| 'number'
	| 'integer'
	| 'object'
	| 'array'
	| 'tuple'
	| 'ref'
	| 'and'
	| 'or';

Depending on which type is used, other properties in NodeType will be required. In fact, the NodeType is defined as:

type NodeType =
	| AnyType
	| NullType
	| BooleanType
	| StringType
	| NumberType
	| IntegerType
	| ObjectType
	| ArrayType
	| TupleType
	| RefType
	| AndType
	| OrType;

These types have an optional name (string) property which can be converted to be required using NamedType<T = NodeType>. This is useful when converting to other type systems where at least the top-most types must have names (like JSON Schema definitions or exported TypeScript types/interfaces), and is used by the NodeDocument, which is what conversion packages should use:

interface NodeDocument
{
	version: 1; // core-types only has version 1 so far
	types: Array< NamedType >;
}

The types also have optional annotation properties title (string), description (string), examples (string or array of strings), default (string), see (string or array of strings) and comment (string).

All types except NullType, AndType and OrType can have two properties const (of type T) or enum (of type Array<T>). The T depends on the NodeType. These have the same semantics as in JSON Schema, meaning a const value is equivalent of an enum with only that value. The enum can be seen as a type literal union in TypeScript.

any type

The AnyType matches any type. Its const and enum properties have the element type T set to unknown.

This corresponds to any or unknown in TypeScript, and the empty schema {} in JSON Schema.

Example: { type: 'any' }

null type

The NullType is simply equivalent to the TypeScript, JavaScript and JSON type null.

Example: { type: 'null' }

boolean type

The BooleanType is equivalent to the TypeScript, JavaScript and JSON Boolean (true and false).

The element type T for const and enum is boolean.

Example: { type: 'boolean', const: false }

string type

The StringType is equivalent to the TypeScript, JavaScript and JSON type String.

The element type T for const and enum is string.

Example: { type: 'string', enum: [ "foo", "bar" ] }

number type

core-types distinguishes between NumberType and IntegerType.

In TypeScript, JavaScript and JSON they are both equivalent to Number. In JSON Schema however, integer is a separate type, and can therefore be converted to core-types with maintained type information.

The element type T for const and enum is number.

Example: { type: 'number', enum: [ 17, 42 ] }

object type

The ObjectType is used to describe the TypeScript type Record<string, NodeType> and the JavaScript and JSON type Object. In TypeScript or JavaScript, the keys must only be strings, not numbers or symbols.

The element type T for const and enum is Record<string, any-json-type>, i.e. plain objects.

Two more properties are required for an ObjectType, properties and additionalProperties.

properties is defined as Record<string, { node: NodeType; required: boolean; }>.

additionalProperties is defined as boolean | NodeType. When this is false, no additional properties apart from those defined in properties are allowed, and if true properties are allowed of any type (AnyType). Otherwise additional properties are allowed of the defined NodeType.

Example:

{
	type: 'object',
	properties: {
		name: { node: { type: 'string' }, required: true },
		age: { node: { type: 'number' }, required: true },
		level: { node: { type: 'string', enum: [ 'novice', 'proficient', 'expert' ] }, required: false },
	},
	additionalProperties: false,
}

array type

The ArrayType is used to describe the TypeScript type Array<NodeType> and the JavaScript and JSON type Array.

The element type T for const and enum is Array<any-json-type>, i.e. arrays of JSON-compatible types defined by the NodeType in elementType.

The extra and required property elementType is of type NodeType and defines what types the array can hold.

Example:

{
	type: 'array',
	elementType: { type: 'string' },
}

tuple type

The TupleType describes specific-length arrays where each position has a specific type. It matches the tuple type [A, B, ...] in TypeScript and is an Array in JavaScript and JSON.

The element type T for const and enum is [...any-json-types], i.e. tuples of JSON-compatible types defined by the NodeType in the required elementTypes and additionalItems.

The extra and required properties for TupleType are elementTypes, minItems and additionalItems.

elementTypes is defined as [...NodeType] and describes the valid types for each position in the tuple for the required and individually typed optional tuple elements.

minItems is an integer (TypeScript/JavaScript number) defining the minimum required elements and must not be negative. If this is greater than the number of elementTypes, although valid in core-types per se, some conversions will limit it to the size of elementTypes.

additionalProperties is used to describe optional extra elemenents. It is defined as boolean | NodeType. When this is false, no additional elements are allowed, and if true elements are allowed of any type (AnyType). Otherwise additional elemenets are allowed of the defined NodeType.

Example:

{
	type: 'tuple',
	elementTypes: [
		{ type: 'string' },
		{ type: 'boolean' }, // Optional, because minItems is 1
	],
	minItems: 1,
	additionalItems: { type: 'number' },
}

ref type

The RefType describes references to other named types. Exactly what this means is up to the implementation of the user of core-types, but it is recommended that a reference type in a list of NodeTypes refers to a named type within that list. This corresponds to TypeScript named types being referred to in the same file as in which the type is defined, or JSON Schema $ref references only referring to #/definitions/* types.

A RefType has a required property ref which is a string corresponding to the name of the reference.

Example:

[
	{
		name: 'User',
		type: 'object',
		properties: {
			name: { node: { type: 'string' }, required: true },
			id: { node: { type: 'number' }, required: true },
		},
		additionalProperties: true,
	},
	{
		name: 'UserList',
		type: 'array',
		elementType: { type: 'ref', ref: 'User' },
	},
]

union type

The OrType describes a union of other types. This is equivalent to union types in TypeScript (e.g. number | string) and anyOf in JSON Schema.

An OrType has a required property or which is defined as Array<NodeType>.

Example:

{
	type: 'or',
	or: [
		{ type: 'string' },
		{ type: 'number' },
		{ type: 'ref', ref: 'IdType' }, // Defined somewhere...
	},
}

intersection type

The AndType describes an intersection of other types. This is equivalent to intersection types in TypeScript (e.g. A & B) and allOf in JSON Schema.

An AndType has a required property and which is defined as Array<NodeType>.

Example:

[
	{
		name: 'CommentWithId',
		type: 'and',
		and: [
			{ type: 'ref', ref: 'Comment' },
			{ type: 'ref', ref: 'WithId' },
		},
	},
	{
		name: 'Comment',
		type: 'object',
		properties: {
			line: { node: { type: 'string' }, required: true },
			user: { node: { type: 'ref', ref: 'User' }, required: true },
		},
		additionalProperties: false,
	},
	{
		name: 'WithId',
		type: 'object',
		properties: {
			id: { node: { type: 'string' }, required: true },
		},
		additionalProperties: false,
	},
]