Two functions are exported: valuesOf
and propertiesOf
. (funny enough neither of them exist, just check index.js yourself 😀).
import { propertiesOf, valuesOf } from 'ts-reflection';
function valuesOf<T>(): T[]
valuesOf
takes one type argument T
(a union type usually) and returns all possible literal values of such type:
import { valuesOf } from 'ts-reflection';
type UnionType = 'string value' | 1 | true | Symbol.toStringTag;
// You can use valuesOf utility to get all the possible union type values
const unionTypeValues = valuesOf<UnionType>(); // ['string value', 1, true, Symbol.toStringTag]
In case the union type does not contain any literal types, valuesOf
will return an empty array:
type UnionType = string | number | boolean;
const unionTypes: UnionType[] = valuesOf<UnionType>(); // []
In case the literal types are "shadowed" by non-literal ones, the literal types will not be present in the array:
// "number" in union type will shadow all the numeric literals
type UnionType = 'primary' | 'secondary' | 1 | 2 | number;
const unionTypes: UnionType[] = valuesOf<UnionType>(); // ['primary', 'secondary']
// "string" in union type will shadow all the string literals
type UnionType = 'primary' | 'secondary' | 1 | 2 | string;
const unionTypes: UnionType[] = valuesOf<UnionType>(); // [1, 2]
valuesOf
also works nicely with enums
, you no longer need to hack any Object.keys
calls:
enum MyEnum {
NO = 0,
MAYBE = 1,
YES = 2
}
const valuesOfMyEnum = valuesOf<MyEnum>(); // [0, 1, 2]
valuesOf
will expand boolean
type into true
and false
:
type UnionType = 'string value' | boolean;
const values = valuesOf<UnionType>(); // ['string value', true, false]
The type that you pass to valuesOf
must not be a type parameter! In other words:
function doMyStuff<T>(value: unknown) {
// Bad, T is a type argument and will depend on how you call the function
const typeValues = valuesOf<T>();
// Good, MyUnionType is not a type parameter
const typeValues = valuesOf<MyUnionType>();
}
function propertiesOf<T>(...queries: PropertyQuery[]): (keyof T)[]
propertiesOf
takes one type argument T
and an (optional) list of PropertyQueries
(these allow fine-grained access to what properties you want to list).
The type that you pass to propertiesOf
must not be a type parameter either! (see above)
If called with no arguments, it returns all public
property names of a type (all interface properties are public
):
interface MyInterface {
property: number;
anotherProperty: string;
}
const properties = propertiesOf<MyInterface>(); // ['property', 'anotherProperty']
enum MyEnum {
NO = 0,
MAYBE = 1,
YES = 2
}
const propertiesOfMyEnum = propertiesOf<typeof MyEnum>(); // ['NO', 'MAYBE', 'YES']
When using propertiesOf
with enums it's important to include the typeof
operator!
Although the output of propertiesOf
will be the same whether you use typeof
or not, the type of the resulting array will be wrong if you don't use it:
// When called with typeof, the type of 'properties' is correct: ('NO' | 'MAYBE' | 'YES')[]
const properties = propertiesOf<typeof MyEnum>();
// When called without typeof, the type of properties is incorrect!
// It will actually be an array of properties of number type since
// MyEnum refers to a value of MyEnum rather than the MyEnum itself
const propertiesOfMyEnumWithoutTypeof = propertiesOf<MyEnum>();
propertiesOf
will return the list of all public
class properties:
class MyClass {
private id: string;
protected name: string;
public displayName: sting;
}
const properties = propertiesOf<MyClass>(); // ['displayName']
When propertiesOf
is called with one PropertyQuery
, it returns all the properties that match that query. Here is how such a query looks:
interface PropertyQuery {
public?: boolean;
protected?: boolean;
private?: boolean;
readonly?: boolean;
optional?: boolean;
}
Here are some examples of such queries:
// Get all the private properties
const privateProperties = propertiesOf<MyClass>({ private: true });
// Get all readonly properties
const readonlyProperties = propertiesOf<MyClass>({ readonly: true });
// Get all non-readonly properties
const nonReadonlyProperties = propertiesOf<MyClass>({ readonly: false });
// Get all optional properties
const optionalProperties = propertiesOf<MyClass>({ optional: true });
// Get all required properties
const requiredProperties = propertiesOf<MyClass>({ optional: false });
// Get all readonly optional properties
const readonlyOptionalProperties = propertiesOf<MyClass>({ readonly: true, optional: true });
// Get all readonly optional properties that are not public
const readonlyOptionalProperties = propertiesOf<MyClass>({ readonly: true, optional: true, public: false });
// Get all required properties that are not public
const readonlyOptionalProperties = propertiesOf<MyClass>({ optional: false, public: false });
When called with multiple queries, propertiesOf
will return all properties that match at least one of the queries.
Here are some examples of such queries:
// Get all optional or readonly properties
const optionalOrReadonlyProperties = propertiesOf<MyClass>({ optional: true }, { readonly: true });
// Get all private or protected properties
const privateOrProtectedProperties = propertiesOf<MyClass>({ private: true }, { protected: true });