@cubux/types

Utility types


Keywords
typescript, typescript-definitions
License
MIT
Install
npm install @cubux/types@1.0.0

Documentation

@cubux/types

NPM latest

Utility types.

Install

npm i @cubux/types

API

AnyCode

Base "catch all" code identifier for CodeOf.

type CountryCode = CodeOf<'Country'>;
interface Country {
  readonly code: CountryCode;
}

function f(code: AnyCode) {}

function fCountry(country: Country) {
  f(country.code);
}

AnyId

Base "catch all" numeric identifier for IdOf.

type UserId = IdOf<'User'>;
interface User {
  readonly id: UserId;
}

function f(id: AnyId) {}

function fUser(user: User) {
  f(user.id);
}

AnyKey

Base "catch all" key-like identifier to be compatible with React key type, AnyId, AnyUuid, AnyCode and NominalType.

AnyUuid

Base "catch all" UUID for UuidOf.

type UserUuid = UuidOf<'User'>;
interface User {
  readonly uuid: UserUuid;
}

function f(uuid: AnyUuid) {}

function fUser(user: User) {
  f(user.uuid);
}

AssignableKeys<T, V>

Get keys of T which V value can be assigned to.

Example:

interface I {
  N: null;
  i: number;
  si?: number | string;
  b?: boolean;
}

type TN = AssignableKeys<I, null>;
// "N"

type Tn = AssignableKeys<I, number>;
// "i" | "si"

type Ts = AssignableKeys<I, string>;
// "si"

type Tb = AssignableKeys<I, boolean>;
// "b"

type Tu = AssignableKeys<I, undefined>;
// "si" | "b"

type Tsn = AssignableKeys<I, string | number>;
// "si"

type TuN = AssignableKeys<I, undefined | null>;
// never

CompatibleKeys<T, V>

Which keys of T are symmetrically compatible with type V.

interface I {
  a: string;
  b?: string;
  c: number;
  d?: number | null;
}

type I1 = CompatibleKeys<I, string>;
// 'a'

type I2 = CompatibleKeys<I, string | undefined>;
// 'b'

type I3 = CompatibleKeys<I, undefined>;
// never

type I4 = CompatibleKeys<I, number>;
// 'c'

type I5 = CompatibleKeys<I, null>;
// never

CodeOf<T extends string>

String code identifier generic.

type CountryCode = CodeOf<'Country'>;

DenyKeys<T, P extends keyof any>

Template type guard helper to deny given keys P in given type T.

Example:

function foo<T extends object & DenyKeys<T, 'x' | 'y'>>(data: T) {
  return null;
}

foo(42);
//  ~~
// TS2345: Argument of type 'number' is not assignable to parameter of
// type 'never'.

foo({ a: 1, b: 2, x: 42 });
//                ~
// TS2322: Type 'number' is not assignable to
// type 'readonly [never, "Property is Denied", "x"]'.

foo({ a: 1, b: 2, x: null, y: undefined });
//                ~        ~
// TS2322: Type 'null' is not assignable to
// type 'readonly [never, "Property is Denied", "x"]'.
// TS2322: Type 'undefined' is not assignable to
// type 'readonly [never, "Property is Denied", "y"]'.

DenyOverlappedKeys<A, B>

Intersection of two types denying overlapping keys.

interface A {
  x: number;
}
interface B {
  y: string;
}

type A = DenyOverlappedKeys<A, B>;
// A & B

type B = DenyOverlappedKeys<A, { y: string, x?: number }>;
// never

ExplicitProps<T, K extends keyof T = keyof T>

Create new type from T with only given keys K making all explicit. This differs from Required<Pick<T, K>> so optional keys x?: V become x: V | undefined instead of x: V as Required does.

interface I {
  x?: number;
  y?: string | undefined;
  z: boolean;
}

type A = ExplicitProps<I>;
// {
//   x: number | undefined;
//   y: string | undefined;
//   z: boolean;
// }

type B = ExplicitProps<I, 'x'>;
// { x: number | undefined; }

type C = ExplicitProps<I, 'y' | 'z'>;
// {
//   y: string | undefined;
//   z: boolean;
// }

Falsy

All possible types which equals to false in Boolean context.

HasRequiredKeys<T>

Whether the given type T has any required keys.

type A = HasRequiredKeys<{ x?: number }>;
// false

type B = HasRequiredKeys<{ x?: number; y: number | undefined }>;
// true

IdOf<T extends string>

Numeric identifier generic.

type UserId = IdOf<'User'>;

IfAssignable<Receiver, Value, Then = true, Else = never>

If a value of type Value can be assigned to a receiver of type Receiver, then results to type Then, otherwise to type Else.

type A = IfAssignable<number | string, number>;
// true

type B = IfAssignable<number | string, string>;
// true

type C = IfAssignable<number | string, boolean>;
// never

type D = IfAssignable<number, number | string>;
// never

IfEquals<X, Y, Then = true, Else = never>

Type equivalence check.

If types X and Y are equivalent, the results to type Then, otherwise results to type Else.

NominalType<Base, Subject extends string>

Generic nominal type.

type UserId = NominalType<number, 'User'>;

NominalTypeFormat<Base, Subject extends string, Format extends string | symbol>

Generic nominal type with distinct format.

type UserEmail = NominalTypeFormat<string, 'User', 'email'>;

ObjectEntries<T>

The type that Object.entries(o: T) should to return in some cases.

interface I {
  a: number;
  b?: string;
}

type E = ObjectEntries<I>;
// readonly (
//   | readonly ["a", number]
//   | readonly ["b", string | undefined]
// )[]

PartialRest<T, Keep extends keyof T>

Keep given props as is and make all the rest props optional.

interface I {
  x: number;
  y: string;
  z?: number;
}

type T = PartialRest<I, 'x'>;
// {
//   x: number;
//   y?: string | undefined;
//   z?: number | undefined;
// }

PartialSome<T, K extends keyof T>

Make given props optional and keep all the rest props as is.

interface I {
  x: number;
  y: string;
  z?: number;
}

type T = PartialSome<I, 'y'>;
// {
//   x: number;
//   y?: string | undefined;
//   z?: number | undefined;
// }

PickOptional<T>

Pick only optional props.

interface I {
  x: number;
  y: string;
  z?: boolean;
  t?: Date | null;
}

type A = PickOptional<I>;
// {
//   z?: boolean | undefined;
//   t?: Date | null | undefined;
// }

PickRequired<T>

Pick properties which are required.

interface I {
  x: number;
  y: number | undefined;
  z?: number;
}

type R = PickRequired<I>;
//  {
//    x: number;
//    y: number | undefined;
//  }

PickWritable<T>

Pick writable properties of T.

Returns properties of T which are writable, t.i. has no readonly attribute.

interface A {
  readonly x: number;
  readonly y: number;
  z: number;
  t: number;
}

type T = PickWritable<A>;
// {
//   z: number;
//   t: number;
// }

RequiredKeys<T, K extends keyof T = keyof T>

Pick keys which are required.

interface I {
  x: number;
  y: number | undefined;
  z?: number;
}

type R = RequiredKeys<I>;
// 'x' | 'y'

RequireProps<T, K extends keyof T>

Make the given properties required and keep all the rest as is.

interface I {
  x?: number;
  y?: string | undefined;
  z: number;
  t: string | undefined;
}

type A = RequireProps<I, 'x'>;
// {
//   x: number | undefined;
//   y?: string | undefined;
//   z: number;
//   t: string | undefined;
// }

type B = RequireProps<I, 'y'>;
// {
//   x?: number;
//   y: string | undefined;
//   z: number;
//   t: string | undefined;
// }

type C = RequireProps<I, 'x' | 'y'>;
// {
//   x: number | undefined;
//   y: string | undefined;
//   z: number;
//   t: string | undefined;
// }

ToObject<T>

Try to map given type into single object type. This can help in some cases, for example with conjunction type A & B.

interface A {
  a: number;
}
interface B {
  b: string;
}

type C = ToObject<A & B>;
// {
//   a: number;
//   b: string;
// }

UnionToIntersection<U>

Convert Union to Intersection.

type C = UnionToIntersection<A | B>;
// A & B

UuidOf<T extends string>

UUID generic.

type UserUuid = UuidOf<'User'>;

WritableKeys<T>

Get those keys of T which don't have readonly attribute.

interface A {
  readonly x: number;
  readonly y: number;
  z: number;
  t: number;
}

type T = WritableKeys<A>;
// 'z' | 't'