Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
inferred-types
Advanced tools
A collection of Typescript utilities which try to preserve as much strong and narrow typing as is possible. In many cases, these type utilities will be paired with a runtime function which provides a runtime mirror to help keep both design time types and runtime values in sync.
All types -- as well as any pairing runtime functions -- are intended to be "self documenting" as much as is possible. This means that they will at least have a description comment which your editor should expose as a popover. In some cases, there are also code examples included in these comments to further flesh out intended use.
To keep things DRY, the documentation here will be kept to a minimum. This README is intended more as a high level introduction of scope and structure of this repo than documentation.
Under the src/
folder you'll find the the following subdirectories:
constants
- a set of runtime constants that can provide utility to both runtime functions as well as provide foundation for enumerated types.types
- this folder represents the heart of the repo in the form of type utilities and is further broken down by an attempt at functional classification that hopefully aides somewhat in feature discovery.runtime
- this is where you'll find runtime functions which mutate state while taking care to provide as much as type information that compliments the runtime environment as is possible.You will find many runtime functions like ensureleading(str, substring)
which have a similarly named type (in this case EnsureLeading<TStr, TSubstring>
). This is no accident and at some future point there may even be something approximating 1:1 parity.
This connection between the type system and the runtime environment allows both a harmonization of variables across both environments and helps to ensure their consistency but it the runtime environment also often really needs strong type utilities to extract out narrow type definitions in the runtime environment.
What follows is not meant to be comprehensive set of examples but rather just a sampling that hopefully gives some perspective on the breadth of scope of this library.
PascalCase<T>
, CamelCase<T>
, SnakeCase<T>
, and KebabCase<T>
to convert a string to one of several familiar naming conventionsAllCaps<T>
to make all alphanumeric characters into their uppercase variantConvert the type and value of a variable from it's singular form to it's plural form:
import { pluralize } from "inferred-types";
// "people"
const people = pluralize("person");
Note: not only does this utility provide all major grammatical rules used in conversion but has a dictionary of common exceptions it will use too.
it's often desireable to ensure that a string starts with or ends with a given string
the inverse can also be useful (aka, to ensure a string does not start or end with a given string literal)
this library provides EnsureLeading
, EnsureTrailing
, StripLeading
, and StripTrailing
utilities to meet these type needs
import type { EnsureLeading } from "inferred-types";
// "start-${string}"
type T1 = EnsureLeading<string, "start-">;
// "start-with"
type T2 = EnsureLeading<"start-with", "start-">;
// "start-with"
type T3 = EnsureLeading<"with", "start-">;
Alpha
, NumericChar
, Whitespace
, Consonants
, etc. try to represent character set building blocks that we may have to isolate on for our own types definitionsUrl
, IpAddress
, CSV
, DotPath
, Hexadecimal
, ZipCode
, and DomainName
attempt to provide an out of the box type for common data structure patterns we find in the real worldIso3166_Alpha2
, Iso3166_Alpha3
, ...isIso3166Alpha2()
, isIsoAlpha3()
, type guards ...Iso8601DateTime
, Iso8601Date
, Iso8601Time
, ...isIsoDateTime()
, isIsoDate()
, isIsoTime()
, ...const matcher = infer("{{ string }} is a {{ infer foo }} utility, that {{ infer bar }}");
// { foo: "fancy"; bar: "thinks it's better than you!"}
const fooBar = matcher("infer is a fancy utility, that thinks it's better than you!")
Add<A,B>
, Subtract<A,B>
, Increment<T>
, Decrement<T>
utilities to work with numeric types (or even numeric string literals)Length<T>
utilityInteger<T>
; ensure a float value with Float<T>
LessThan<A,B>
, LessThanOrEqual<A,B>
, and GreaterThan<A,B>
Abs<T>
AfterFirst
, First
, Last
to index into a tuple / list valueAsArray<T>
to ensure an array value for TFlatten<T>
to flatten an arraySlice<T,S,E>
to take out a subset of elements in a listReverse
to reverse a listAssume a base type of Obj
:
type Obj = {
n1: number;
n2: 2;
n3: 3;
success: true;
s1: string;
s2: "hello";
}
We can get a union of string literals representing the keys on the object whose value extends some value:
import type { KeysWithValue, KeysWithoutValue } from "inferred-types";
// "s1" | "s2"
type S = KeysWithValue<Obj, string>;
// "success" | "n1" | "n2"
type N = KeysWithoutValue<Obj, string>;
though less used, you can also use
KeysEqualValue
andKeysNotEqualValue
for equality matching
If you'd prefer to mutate the object's type rather than just identify the keys which extend a value you can do this with: WithValue
and WithoutValue
:
import type { WithValue, WithoutValue } from "inferred-types";
// { s1: string; s2: "hello" }
type S = WithValue<Obj, string>;
// { success: true; n1: number; n2: 2; n3: 3 }
type N = WithoutValue<Obj, string>;
And at runtime:
// { foo: "hi" }
const foo = withoutValue("number")({ foo: "hi", bar: 42, baz: 99 });
// { bar: 42 }
const bar = withoutValue("number(42,55,66)")({ foo: "hi", bar: 42, baz: 99 });
// { foo: "hi", bar: 42 }
const fooBar = withoutKeys("baz")({ foo: "hi", bar: 42, baz: 99 });
// { foo: "hi", bar: 42 }
const fooBar2 = withKeys("foo", "bar")({ foo: "hi", bar: 42, baz: 99 })
Required
or Optional
keystype Obj = { foo: string; bar?: string; baz?: number };
// "foo"
type ReqKeys = RequiredKeys<Obj>;
// ["foo"]
type ReqKeyTup = RequiredKeysTuple<Obj>;
// "bar" | "baz"
type OptKeys = OptionalKeys<Obj>;
// ["bar", "baz"]
type OptKeyTup = OptionalKeysTuple<Obj>;
type Reduced =
If you are using this library and would like to take the next step of contributing; that effort is welcome but please do make sure to always provide both runtime and type tests for any code changes which you submit as a pull request.
See the plentiful examples that exist under the tests/
folder for inspiration.
Note: as of 2024 I'm also starting to add "type performance" tests; not an absolute requirement but in general adding something like you'll find in the benches/
folder for any new type utility would be appreciated.
This repo is offered under the highly permissive MIT license.
FAQs
Functions which provide useful type inference on TS projects
We found that inferred-types demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.