@telokys/ts-meta-types
v2.8.0
Published
Type helpers for TypeScript
Readme
ts-meta-types
Collection of useful TypeScript helpers for manipulating or altering types.
- Install
- Usage
- API
Install
npm install -D @telokys/ts-meta-typesUsage
import { ReplaceType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second: boolean;
third: string;
}
type MyNewData = ReplaceType<MyData, boolean, string>;
//=> interface MyNewData {
// first: number;
// second: string;
// third: string;
// }API
Select keys from an interface
KeysOfType<Terface, Filter>
Source : KeysOfType.ts.
Will return a union of all Terface's keys of type Filter.
Example:
import { KeysOfType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second: boolean;
third: string;
fourth: boolean;
}
type MyKeys = KeysOfType<MyData, boolean>;
//=> "second" | "fourth"KeysWhereTypeCanBe<Terface, Filter>
Source : KeysWhereTypeCanBe.ts.
Returns a union of all Terface's keys for which Filter is assignable to the property.
Be careful: As opposed to KeysOfType<Terface, Filter> this WILL pick nullable properties EVEN IF undefined is not in Filter.
Adding undefined to Filter will pick ALL nullable properties!
Example:
import { KeysWhereTypeCanBe } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
fifth: number | Date;
sixth: string | Date;
seventh?: Date;
}
type MyKeys = KeysWhereTypeCanBe<MyData, boolean | string>;
//=> "second" | "third" | "fourth" | "sixth"
// Be careful if you add undefined to Filter
type MyOtherKeys = KeysWhereTypeCanBe<MyData, boolean | string | undefined>;
//=> "second" | "third" | "fourth" | "sixth" | "seventh"KeysNotOfType<Terface, Filter>
Source : KeysNotOfType.ts.
Will return a union of all Terface's keys NOT of type Filter.
Example:
import { KeysNotOfType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second: boolean;
third: string;
fourth: boolean;
}
type MyKeys = KeysNotOfType<MyData, boolean>;
//=> "first" | "third"KeysWhereTypeCannotBe<Terface, Filter>
Source : KeysWhereTypeCannotBe.ts.
Returns a union of all Terface's keys for which Filter is NOT assignable to the property.
This helper is also aliased as KeysWhereTypeCantBe<Terface, Filter>.
Be careful: As opposed to KeysOfType<Terface, Filter> this WILL omit nullable properties EVEN IF undefined is not in Filter.
Adding undefined to Filter will omit ALL nullable properties!
Example:
import { KeysWhereTypeCannotBe } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
fifth: number | Date;
sixth: string | Date;
seventh?: Date;
}
type MyKeys = KeysWhereTypeCannotBe<MyData, boolean | string>;
//=> "first" | "fifth" | "seventh"
// Be careful if you add undefined to Filter
type MyOtherKeys = KeysWhereTypeCannotBe<MyData, boolean | string | undefined>;
//=> "first" | "fifth" // Not "seventh" because it is nullablePick specific properties from an interface
PickMembers<Terface, K>
Source : PickMembers.ts.
Returns an interface containing the properties for which the key is specified in K.
Example:
import { PickMembers } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third?: string;
}
type MyNewData = PickMembers<MyData, "first" | "third">;
//=> interface MyNewData {
// first: number;
// third?: string;
// }PickMembersOfType<Terface, Filter>
Source : PickMembersOfType.ts.
Returns an interface containing the properties for which the value is assignable to Filter.
Be careful: this won't pick nullable properties if undefined is not in Filter. See PickMembersWhereTypeCanBe<Terface, Filter> if you don't want this behavior
Example:
import { PickMembersOfType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
}
type MyNewData = PickMembersOfType<MyData, boolean | string>;
//=> interface MyNewData {
// third: boolean;
// fourth: string;
// }
// Add undefined to the filter if you want to pick second
type MyOtherNewData = PickMembersOfType<MyData, boolean | string | undefined>;
//=> interface MyOtherNewData {
// second?: boolean;
// third: boolean;
// fourth: string;
// }PickVoidMembers<Terface>
Source : PickMembersOfType.ts.
Returns an interface containing the properties for which the value is void.
This is a shortcut for PickMembersOfType<Terface, void>.
Example:
import { PickVoidMembers } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: void;
fourth: string;
}
type MyNewData = PickVoidMembers<MyData>;
//=> interface MyNewData {
// third: void;
// }PickMembersWhereTypeCanBe<Terface, Filter>
Source : PickMembersWhereTypeCanBe.ts.
Returns an interface containing the properties for which Filter is assignable to the property.
Be careful: As opposed to PickMembersOfType<Terface, Filter> this WILL pick nullable properties EVEN IF undefined is not in Filter.
Adding undefined to Filter will pick ALL nullable properties!
Example:
import { PickMembersWhereTypeCanBe } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
fifth?: number;
}
type MyNewData = PickMembersWhereTypeCanBe<MyData, boolean | string>;
//=> interface MyNewData {
// second?: boolean; // Kept because can be boolean
// third: boolean;
// fourth: string;
// }
// Be careful if you add undefined to Filter
type MyOtherNewData = PickMembersWhereTypeCanBe<MyData, boolean | string | undefined>;
//=> interface MyOtherNewData {
// second?: boolean;
// third: boolean;
// fourth: string;
// fifth?: number; // Oops, was this expected?
// }PickMembersNotOfType<Terface, Filter>
Source : PickMembersNotOfType.ts.
Returns an interface containing the properties for which the value is NOT assignable to Filter.
Be careful: this WILL pick nullable properties if undefined is not in Filter.
Example:
import { PickMembersNotOfType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
}
type MyNewData = PickMembersNotOfType<MyData, boolean | string>;
//=> interface MyNewData {
// first: number;
// second?: boolean; // Picked because undefined is not in Filter
// }
// Add undefined to the filter if you don't want to pick second
type MyOtherNewData = PickMembersNotOfType<MyData, boolean | string | undefined>;
//=> interface MyOtherNewData {
// first: number;
// }PickNonVoidMembers<Terface>
Source : PickMembersNotOfType.ts.
Returns an interface containing the properties for which the value is NOT void.
This is a shortcut for PickMembersNotOfType<Terface, void>.
Example:
import { PickNonVoidMembers } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: void;
fourth: string;
}
type MyNewData = PickNonVoidMembers<MyData>;
//=> interface MyNewData {
// first: number;
// second?: boolean;
// fourth: string;
// }PickMembersWhereTypeCannotBe<Terface, Filter>
Source : PickMembersWhereTypeCannotBe.ts.
Returns an interface containing the properties for which Filter is NOT assignable to the value.
This helper is also aliased as PickMembersWhereTypeCantBe<Terface, Filter>.
Be careful: As opposed to PickMembersNotOfType<Terface, Filter> this WILL omit nullable properties EVEN IF undefined is not in Filter.
Adding undefined to Filter will omit ALL nullable properties!
Example:
import { PickMembersWhereTypeCannotBe } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
fifth: number | Date;
sixth: string | Date;
seventh?: Date;
}
type MyNewData = PickMembersWhereTypeCannotBe<MyData, boolean | string>;
//=> interface MyNewData {
// first: number;
// fifth: number | Date;
// seventh?: Date;
// }
// Be careful if you add undefined to Filter
type MyOtherNewData = PickMembersWhereTypeCannotBe<MyData, boolean | string | undefined>;
//=> interface MyOtherNewData {
// first: number;
// fifth: number | Date;
// // seventh is omitted because it is nullable
// }Modify an interface
ReplaceType<Terface, Filter, New>
Source : ReplaceType.ts.
Returns an interface where all properties assignable to Filter are now of type New.
Be careful: this won't replace nullable properties if undefined is not in Filter.
Example:
import { ReplaceType } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
}
type MyNewData = ReplaceType<MyData, boolean | string, number>;
//=> interface MyNewData {
// first: number;
// second?: boolean; // Not replaced : undefined is not in Filter
// third: number;
// fourth: number;
// }
type MyOtherNewData = ReplaceType<MyData, boolean | string | undefined, number>;
//=> interface MyOtherNewData {
// first: number;
// second: number; // Replaced BUT NOT NULLABLE ANYMORE!
// third: number;
// fourth: number;
// }ReplaceTypeIfCanBe<Terface, Filter, New>
Source : ReplaceType.ts.
Returns an interface where all properties P for which Filter is assignable to P are now of type New.
Be careful: this will replace ALL nullable properties if undefined is in Filter.
Be careful: this is a strict replacement. Adding boolean to Filter will match boolean | number and replace it with New, not with New | number.
Example:
import { ReplaceTypeIfCanBe } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third: boolean;
fourth: string;
fifth: number | Date;
sixth: string | Date;
seventh?: Date;
}
type MyNewData = ReplaceTypeIfCanBe<MyData, boolean | string, number>;
//=> interface MyNewData {
// first: number;
// second: number; // Strictly replaced : not nullable anymore
// third: number;
// fourth: number;
// fifth: number | Date;
// sixth: number; // Strictly replaced : Can't be Date anymore
// seventh?: Date;
// }
// Adding undefined to the filter is dangerous: it will replace all nullable properties
type MyOtherNewData = ReplaceTypeIfCanBe<MyData, boolean | string | undefined, number>;
//=> interface MyOtherNewData {
// first: number;
// second: number;
// third: number;
// fourth: number;
// fifth: number | Date;
// sixth: number;
// seventh: number; // Oops! Didn't expect this one
// }MakeRequired<Terface, K>
Source : MakeRequired.ts.
Will return an interface where all properties in the union K are required. All properties not in the union K are left as is.
This helper will not recurse at all!
Example:
import { MakeRequired } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
third?: string;
deep?: {
key: number;
key2?: string;
};
}
type MyNewData = MakeRequired<MyData, "second" | "deep">;
//=> interface MyNewData {
// first: number;
// second: boolean; // Required
// third?: string; // Untouched : Not in K
// deep: { // Required
// key: number;
// key2?: string; // Untouched : No recursion
// };
// }Note: The difference with TS native Required is that Required<Terface> will make ALL properties of Terface required. By using MakeRequired<Terface, K> you can explicitly specify the properties you want required.
MakeOptional<Terface, K>
Source : MakeOptional.ts.
Will return an interface where all properties in the union K are optional. All properties not in the union K are left as is.
This helper will not recurse at all!
Example:
import { MakeOptional } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second: boolean;
third?: string;
deep: {
key: number;
key2?: string;
};
}
type MyNewData = MakeOptional<MyData, "first" | "deep">;
//=> interface MyNewData {
// first?: number; // Optional
// second: boolean; // Untouched : Not in K
// third?: string; // Untouched : Not in K
// deep?: { // Optional
// key: number; // Untouched : No recursion
// key2?: string;
// };
// }Note: The difference with TS native Partial is that Partial<Terface> will make ALL properties of Terface optional. By using MakeOptional<Terface, K> you can explicitly specify the properties you want optional.
MakeNonNull<Terface, K>
Source : MakeRequired.ts.
Makes specified properties non-null, keeping others unchanged. Properties not in K retain their original types.
Terface - The interface/type to modifyK - Keys to make non-null (defaults to all keys)
Example:
interface Data {
value: string | null;
id: number | null;
metadata?: string | null;
deep: null | {
key: number | null;
key2: string;
};
}
type Data_NonNull = MakeNonNull<Data, "value" | "metadata" | "deep">;
// {
// value: string; // Made non-null
// id: number | null; // Unchanged: Not included in the K argument
// metadata?: string; // Made non-null
// deep: { // Made non-null
// key: number | null; // Unchanged: doesn't recurse
// key2: string; // Unchanged
// };
// }Types
ArrayElement<ArrayType>
Source : ArrayElement.ts.
Extracts the element type from an array type.
Example:
type StringArray = string[];
type Element = ArrayElement<StringArray>;
// ^ => type Element = string
type ReadonlyNumberArray = readonly number[];
type NumberElement = ArrayElement<ReadonlyNumberArray>;
// ^ => type NumberElement = numberDeepRequired<Terface>
Source : MakeRequired.ts.
Makes all properties in a type required recursively, including nested objects.
Basically a deep version of Required
Terface - The interface/type to make deeply required
Example:
interface Nested { data?: { value?: number } }
type RequiredType = DeepRequired<Nested>; // { data: { value: number } }Scalar
Source : Scalar.ts.
Shortcut for string | number | boolean.
NullableScalar
Source : Scalar.ts.
Shortcut for Scalar | null.
OptionalScalar
Source : Scalar.ts.
Shortcut for Scalar | undefined.
OptionalNullableScalar
Source : Scalar.ts.
Shortcut for NullableScalar | undefined.
ValueOf<Terface>
Source : ValueOf.ts.
Returns a union containing the types of all values of Terface.
Example:
import { ValueOf } from "@telokys/ts-meta-types";
interface MyData {
first: number;
second?: boolean;
duplicate: boolean;
third?: string;
deep?: {
key: number;
key2?: string;
deepAgain?: {
alpha: string;
beta?: string;
};
};
}
type MyNewData = ValueOf<MyData>;
//=> string
// | number
// | boolean
// | {
// key: number;
// key2?: string;
// deepAgain?: {
// alpha: string;
// beta?: string;
// };
// }
// | undefinedType Generators
RangedUnion<Min, Max, Step=1>
Source : RangedUnion.ts.
Creates a union type of numbers within a specified range with an optional step increment.
Min - The minimum value of the range (inclusive)
Max - The maximum value of the range (inclusive)
[Step=1] - The increment value between each number in the range
Example:
type Numbers = RangedUnion<0, 5>; // 0 | 1 | 2 | 3 | 4 | 5
type EvenNumbers = RangedUnion<0, 6, 2>; // 0 | 2 | 4 | 6
type AboveTen = RangedUnion<10, 20, 3>; // 10 | 13 | 16 | 19Tuple<Type, N>
Source : Tuple.ts.
Easily creates a tuple containing N elements of type Type.
Example:
type Tuple3 = Tuple<string, 3>;
// ^ => type Tuple3 = [string, string, string]ObjectOf<T>
Source : ObjectOf.ts.
Shortcut for creating Records of type Record<string, T>.
Example:
import { ObjectOf } from "@telokys/ts-meta-types";
// Equivalent to Record<string, boolean>
type MyObject = ObjectOf<boolean>;
//=> {
// [key: string]: boolean;
// }Misc
Debug<Terface>
Source : Debug.ts.
Taken from https://stackoverflow.com/a/57683652/4613742.
Will "clean" an interface in order for the intellisense to properly display the real computed type.
Be careful: This is not recursive.
Example:
Given the following code
import { Debug, MakeRequired, MakeDeepRequired } from "@telokys/ts-meta-types";
interface Test {
test: boolean;
test2?: number;
test3: number;
deep?: {
tmp: string;
tmp2?: string;
}
}
type RawRequired = MakeRequired<Test>;
type RawRequiredDeep = MakeDeepRequired<Test>;
type DebuggedRequired = Debug<RawRequired>;
type DebuggedRequiredDeep = Debug<RawRequiredDeep>;Here the intellisense given by VSCode for the first two types:

As you can see, there are Required<> in someplaces. We have to mentally interpret them.
Do Required apply recursively? I don't want to remember, I want the intellisense to tell me the real type.
Wrapping the type in Debug will display the following:

Now the intellisense is much more helpful. I can instantly see the updated version is doing what I hoped it would.
Note that the
Debughelper is not recursive, as seen on the right image. If you want the recursive version, seeDebugR<Terface>
DebugR<Terface>
Source : Debug.ts.
Taken from https://stackoverflow.com/a/57683652/4613742.
Will recursively "clean" an interface in order for the intellisense to properly display the real computed type.
Example:
Given the following code
import { DebugR, MakeRequired, MakeDeepRequired } from "@telokys/ts-meta-types";
interface Test {
test: boolean;
test2?: number;
test3: number;
deep?: {
tmp: string;
tmp2?: string;
}
}
type RawRequired = MakeRequired<Test>;
type RawRequiredDeep = MakeDeepRequired<Test>;
type RecursivelyDebuggedRequired = DebugR<RawRequired>;
type RecursivelyDebuggedRequiredDeep = DebugR<RawRequiredDeep>;Here the intellisense given by VSCode for the first two types:

As you can see, there are Required<> in someplaces. We have to mentally interpret them.
Do Required apply recursively? I don't want to remember, I want the intellisense to tell me the real type.
Wrapping the type in DebugR will display the following:

Now the intellisense is much more helpful. I can instantly see the updated version is doing what I hoped it would.
