type-ops
Type-ops -- a collection of useful operators to make type-level programming in TypeScript easier.
Table of contents
Compatibility
TypeScript ~2.9.0
, ^3.0.1
.
Install
npm i type-ops
Requirements
For some operators to work properly, strict mode must be enabled.
Dependencies
None.
License
MIT.
TODO
Features
Testing & checking utilities
These types can be used to test an arbitrary type for being conformant to a certain constraint.
expect
Induce a compilation error if TActual
does not resolve to the type of expected
.
Definition
declare const expect: <TActual>() => { toBe(expected: TActual): void; };
Usage
interface I1 {
p1: string;
}
interface I2 {
p1: number;
}
expect<IsSameT<I1, I2>>().toBe(false);
ExpectT
Induce a compilation error if TActual
does not resolve to TExpected
.
Definition
type ExpectT<TActual extends TExpected, TExpected extends boolean> = never;
Usage
interface I1 { p1: string; }
interface I2 { p1: number; }
type E1 = ExpectT<IsSameT<I1, I2>, false>;
IsFalseT
Check if T
is false
.
Does not distribute over unions.
Definition
type IsFalseT<T extends boolean> = IsSameT<T, false>;
IsNeverT
Check if T
is never
.
Does not distribute over unions.
Definition
type IsNeverT<T> = IsSameT<T, never>;
IsNullableT
Check if T
is nullable.
Does not distribute over unions.
Definition
type IsNullableT<T> = IsSubtypeOfT<undefined | null, T>;
IsOptionalT
Check if T
is optional.
Does not distribute over unions.
Definition
type IsOptionalT<T> = IsSubtypeOfT<undefined, T>;
IsSameT
Check if T
and U
are of the same shape.
Does not distribute over unions.
Definition
type IsSameT<T, U> = AndT<IsSubtypeOfT<T, U>, IsSubtypeOfT<U, T>>;
IsSubtypeOfT
Check if T
is a subtype of U
.
Does not distribute over unions.
type IsSubtypeOfT<T, U> = NoDistributeT<T> extends U
? true
: false;
IsTrueT
Check if T
is true
.
Does not distribute over unions.
Definition
type IsTrueT<T extends boolean> = NotT<IsFalseT<T>>;
Property selectors
These types can be thought of as "filters" on property keys of a particular type.
KeyofT
Extract all properties of T
.
Distributes over unions.
Definition
type KeyofT<T> = T extends any
? keyof T
: never;
NotPropertiesOfSubtypeT
Extract all properties of T
which are not a subtype of U
.
Definition
type NotPropertiesOfSubtypeT<T, U> = Exclude<keyof T, PropertiesOfSubtypeT<T, U>>;
NotPropertiesOfTypeT
Extract all properties of T
which are not of the same shape as U
.
Definition
type NotPropertiesOfTypeT<T, U> = Exclude<keyof T, PropertiesOfTypeT<T, U>>;
OptionalPropertiesT
Extract all optional properties of T
.
Definition
type OptionalPropertiesT<T> = {
[K in keyof T]-?: IsOptionalT<T[K]> extends false
? never
: K;
}[keyof T];
PropertiesOfSubtypeT
Extract all properties of T
which are a subtype of U
.
Definition
type PropertiesOfSubtypeT<T, U> = {
[K in keyof T]: IsSubtypeOfT<T[K], U> extends false
? never
: K;
}[keyof T];
PropertiesOfTypeT
Extract all properties of T
which are of the same shape as U
.
Definition
type PropertiesOfTypeT<T, U> = {
[K in keyof T]: IsSameT<T[K], U> extends false
? never
: K;
}[keyof T];
RequiredPropertiesT
Extract all required properties of T
.
Definition
type RequiredPropertiesT<T> = {
[K in keyof T]-?: IsOptionalT<T[K]> extends false
? K
: never;
}[keyof T];
Type modifiers
These are just mapped conditional types.
JsonT
Represent T
after JSON serialization round-trip.
Distributes over unions.
Definition
interface _JsonArrayT<T> extends Array<JsonT<T>> { }
type _CleanT<T> = OmitT<T, PropertiesOfTypeT<T, never>>;
type _JsonObjectT<T> = {
[K in keyof T]: JsonT<T[K]>;
};
type JsonT<T> = T extends string | number | boolean | null
? T
: T extends Function | symbol | undefined
? never
: T extends Array<infer U> | ReadonlyArray<infer U>
? _JsonArrayT<U>
: T extends Map<any, any> | ReadonlyMap<any, any> | WeakMap<any, any> | Set<any> | ReadonlySet<any> | WeakSet<any>
? { }
: T extends { toJSON(key?: any): infer U; }
? U
: _CleanT<_JsonObjectT<T>>;
OmitT
Omit properties K
from T
.
Definition
type OmitT<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
OverwriteT
Overwrite properties K
of T
with matching properties of U
and add properties which are unique to U
.
Definition
type OverwriteT<T, U, K extends keyof T & keyof U = keyof T & keyof U> = OmitT<T, K> & U;
Usage
interface I1 {
p1: string;
p2: string;
p3: string;
}
interface I2 {
p2: number;
p3: number;
p4: number;
}
type I3 = OverrideT<I1, I2>;
const i3: I3 = {
p1: 'v1',
p2: 2,
p3: 3,
p4: 4,
};
PartialDeepT
Recursively make all properties of T
optional.
Definition
interface _PartialDeepArray<T> extends Array<PartialDeepT<T>> { }
interface _PartialDeepReadonlyArray<T> extends ReadonlyArray<PartialDeepT<T>> { }
type _PartialDeepObjectT<T> = {
[K in keyof T]: PartialDeepT<T[K]>;
};
export type PartialDeepT<T> = T extends Array<infer U>
? _PartialDeepArray<U>
: T extends ReadonlyArray<infer U>
? _PartialDeepReadonlyArray<U>
: T extends Function | PrimitiveT
? T
: Partial<_PartialDeepObjectT<T>>;
ReadonlyDeepT
Recursively make all properties of T
readonly.
Definition
interface _ReadonlyDeepArray<T> extends Array<ReadonlyDeepT<T>> { }
interface _ReadonlyDeepReadonlyArray<T> extends ReadonlyArray<ReadonlyDeepT<T>> { }
type _ReadonlyDeepObjectT<T> = {
[K in keyof T]: ReadonlyDeepT<T[K]>;
};
export type ReadonlyDeepT<T> = T extends Array<infer U>
? _ReadonlyDeepArray<U>
: T extends ReadonlyArray<infer U>
? _ReadonlyDeepReadonlyArray<U>
: T extends Function | PrimitiveT
? T
: Readonly<_ReadonlyDeepObjectT<T>>;
ReplaceT
Replace properties K
of T
with matching properties of U
.
Definition
type ReplaceT<T, U, K extends keyof T & keyof U = keyof T & keyof U> = OmitT<T, K> & Pick<U, K>;
Usage
interface I1 {
p1: string;
p2: string;
p3: string;
p4: string;
}
interface I2 {
p2: number;
p3: number;
p4: number;
p5: number;
}
type I3 = ReplaceT<I1, I2, 'p2' | 'p4'>;
const i3: I3 = {
p1: 'v1',
p2: 2,
p3: 'v3',
p4: 4,
};
RequiredDeepT
Recursively make all properties of T
required.
Definition
interface _RequiredDeepArray<T> extends Array<RequiredDeepT<T>> { }
interface _RequiredDeepReadonlyArray<T> extends ReadonlyArray<RequiredDeepT<T>> { }
type _RequiredDeepObjectT<T> = {
[K in keyof T]: RequiredDeepT<T[K]>;
};
export type RequiredDeepT<T> = T extends Array<infer U>
? _RequiredDeepArray<U>
: T extends ReadonlyArray<infer U>
? _RequiredDeepReadonlyArray<U>
: T extends Function | PrimitiveT
? T
: _RequiredDeepObjectT<Required<T>>;
WithMutableT
Make properties K
of T
mutable.
Definition
type WithMutableT<T, K extends keyof T> = ReplaceT<T, MutableT<T>, K>;
WithPartialT
Make properties K
of T
optional.
Definition
type WithPartialT<T, K extends keyof T> = ReplaceT<T, Partial<T>, K>;
WithReadonlyT
Make properties K
of T
readonly.
Definition
type WithReadonlyT<T, K extends keyof T> = ReplaceT<T, Readonly<T>, K>;
WithRequiredT
Make properties K
of T
required.
Definition
type WithRequiredT<T, K extends keyof T> = ReplaceT<T, Required<T>, K>;
WritableDeepT
Recursively make all properties of T
mutable.
Definition
interface _MutableDeepArray<T> extends Array<MutableDeepT<T>> { }
interface _MutableDeepReadonlyArray<T> extends ReadonlyArray<MutableDeepT<T>> { }
type _MutableDeepObjectT<T> = {
[K in keyof T]: MutableDeepT<T[K]>;
};
type MutableDeepT<T> = T extends Array<infer U>
? _MutableDeepArray<U>
: T extends ReadonlyArray<infer U>
? _MutableDeepReadonlyArray<U>
: T extends Function | PrimitiveT
? T
: _MutableDeepObjectT<MutableT<T>>;
MutableT
Make all properties of T
mutable.
Definition
type MutableT<T> = {
-readonly [K in keyof T]: T[K];
};
Aliases and interfaces
ConstructorT
A constructor of TInstance
s from TArguments
.
Definition
type ConstructorT<TInstance = object, TArguments extends any[] = any[]> = new(...args: TArguments) => TInstance;
DictT
A dictionary of TValue
s.
Definition
interface DictT<TValue = any> {
[propertyKey: string]: TValue;
}
FunctionT
A function mapping TArguments
to TResult
.
Definition
type FunctionT<TResult = any, TArguments extends any[] = any[]> = (...args: TArguments) => TResult;
NullableT
Make T
nullable.
Definition
type NullableT<T> = OptionalT<T> | null;
OptionalT
Make T
optional.
Definition
type OptionalT<T> = T | undefined;
PrimitiveT
A primitive.
Definition
type PrimitiveT = string | symbol | number | boolean | undefined | null;
TaggedT
Make tagged type from T
using tag TTag
.
It can be used to create an opaque alias of T
.
Definition
declare const _RAW_TYPE: unique symbol;
declare const _TAG_TYPE: unique symbol;
type TaggedT<T, TTag extends PropertyKey> = T & {
[_RAW_TYPE]: T;
[_TAG_TYPE]: TTag;
};
Usage
type I1 = UniqueT<string, 'A'>;
let i1: I1 = 'v1' as I1;
i1 = 'v2' as I1;
const i11: RawT<I1> = i1;
type I2 = UniqueT<string, 'A'>;
let i2: I2 = 'v4' as I2;
i2 = i1;
i1 = i2;
const i21: RawT<I1> = i1;
type I3 = UniqueT<string, 'B'>;
let i3: I3 = 'v5' as I3;
const i31: RawT<I1> = i1;
type I4 = RetaggedT<U3, 'A'>;
let i4: I4 = i3 as RawT<I3> as I4;
i4 = i1;
i1 = i4;
RawT
Extract raw type of tagged T
.
Distributes over unions.
Definition
type RawT<T> = T extends UniqueT<infer U, infer TTag_>
? U
: T;
TagT
Extract tag from tagged T
.
Distributes over unions.
Definition
type TagT<T> = T extends UniqueT<infer U_, infer TTag>
? TTag
: never;
RetaggedT
Retag a tagged T
using tag TTag
.
Distributes over unions.
Definition
type RetaggedT<T, TTag extends PropertyKey> = T extends TaggedT<infer U, infer TTag_>
? TaggedT<U, TTag>
: TaggedT<T, TTag>;
Logical operators
AndT
Logical "and" of T
and U
.
Distributes over unions.
Definition
type AndT<T extends boolean, U extends boolean> = T extends false
? false
: U extends false
? false
: true;
NotT
Logical "not" of T
.
Distributes over unions.
Definition
type NotT<T extends boolean> = T extends false
? true
: false;
OrT
Logical "or" of T
and U
.
Distributes over unions.
Definition
type OrT<T extends boolean, U extends boolean> = T extends false
? U extends false
? false
: true
: true;
XorT
Logical "xor" of T
and U
.
Distributes over unions.
Definition
type XorT<T extends boolean, U extends boolean> = T extends false
? U extends false
? false
: true
: U extends false
? true
: false;
Miscellaneous utilities
NoDistributeT
Prevent distribution over T
.
Definition
type NoDistributeT<T> = T extends any
? T
: never;
NoInferT
Prevent type inference on T
.
Definition
type NoInferT<T> = T & Pick<T, keyof T>;
Usage
declare const f1: <T>(i1: T, i2: T) => void;
f1({ p1: 'v1', p2: 'v2' }, { p1: 'v1' });
declare const f2: <T>(i1: T, i2: NoInferT<T>) => void;
f2({ p1: 'v1', p2: 'v2' }, { p1: 'v1', p2: 'v2' });
SelectT
Extract a member of a tagged union T
using TTagKey
as a tag property and TValue
as its type.
Definition
type SelectT<T, TTagKey extends keyof T, TTagValue extends T[TTagKey]> = Extract<T, Record<TTagKey, TTagValue>>;
Usage
declare const TAG: unique symbol;
interface I1 {
[TAG]: 'I1';
p1: string;
}
interface I2 {
[TAG]: 'I2';
p1: number;
}
type I3 = I1 | I2;
type A11 = TaggedUnionMemberT<I3, typeof TAG, 'I1'>;