This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* _Explicitly declare modifications_ to an existing object type via a fluent interface which yields a mapping function | |
* from the original data type to the type derived from the modification commands. | |
* | |
* The value over authoring a simple mapping function directly | |
* * harder to make a mistake due to the explicit nature | |
* * easier to read. | |
* | |
* This is _not_ production quality code but rather a _proof of concept_ gist for applying conditional/mapped | |
* types to mapper generation. A real-world usage might involve also generating the type-guard function |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* When implementing the evaluation of a tree of expressions, an environment/context/memory representation is typically passed as an | |
* argument (or injected into the constructor of the interpreter class for OO realizations of the pattern) in order to give the | |
* expressions access to a memory store. | |
* | |
* The *Type* of the memory does not normally relate to any specific constructed expression ex. the memory may be implemented as an | |
* _arbitrary_ dictionary of key/value pairs. As such, there is no way to know if a type or instance of a dictionary of values can | |
* satisfy the needs to a specific constructed expression. | |
* | |
* For example, the following expression reads a number named 'x' from the environment and therefore the expression _requires_ an x of type number |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Logging { | |
let indent = 0; | |
let enabled = false; | |
const indentedMessage = (msg: string) => | |
Array(indent * 2).fill("").join(" ") + msg; | |
export const log = (msg: string) => { | |
if (enabled) | |
console.log(indentedMessage(msg)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Imagine a Fluent Builder where some subset of the fluent methods are valid to call | |
* * after one or more fluent methods have been called | |
* * before one or more fluent methods have been called | |
* * limited number of times. | |
* | |
* There is no way to enforce such constraints in statically typed languages such as C++, C# or Java when using a single builder | |
* class/interface. Developers would need to author many interfaces to represent the different shapes and would likely need to | |
* author many versions of the builder itself (proxies with a specific signature delegating to an underlying source builder). | |
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Demonstrate inferring a strong type signature from the CanJS dynamic view model API. | |
*/ | |
module ReadMe {} | |
module ViewModelTypes { | |
/** Definition of a "class". */ | |
export type Definition = { attributes: any } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Micro Api for building type predicates */ | |
module TypePredicateApi { | |
export type TypePredicate<refined> = (val: any) => val is refined; | |
export type TypeOfTypePredicate<refiner> = refiner extends TypePredicate<infer refined> ? refined : never; | |
export type TypePredicateMap = { [propertyName: string]: TypePredicate<any> } | |
export type ObjectFromTypePredicateMap<map extends { [propertyName: string]: TypePredicate<any> }> = { | |
[propertyName in keyof map]: TypeOfTypePredicate<map[propertyName]>; | |
} | |
/** Create a predicate which tests for an object. */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* **Power of Infer** | |
* Infer allows us to match a type for a structure and unpack the internal structure of that type | |
* into local type variables. This is essentially destructuring/deconstructing/elimination. | |
* | |
* The are two fundamental computation operations | |
* * Building up or constructing types - which can be done with Mapped Types (comprehension). | |
* * Unpacking types - which can be done with the combination of Conditional Types and the use of infer. | |
* | |
* The examples below are the poster-child for this idea of computation through construction/deconstruction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Micro Api for building decoders. */ | |
module DecoderApi { | |
type Unknown = unknown; | |
type ErrorMessage = { kind: "error"; error: string } | |
export const errorMessage = (error: string): ErrorMessage => ({ kind: "error", error }); | |
export type DecodeResult<value> = value | ErrorMessage | |
export const isErrorMessage = <value extends unknown>(result: DecodeResult<value>): result is ErrorMessage => | |
!!result && | |
typeof result === "object" && | |
(result as any).kind === "error"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Yet another demonstration of TypeScript awesomeness | |
* - NonEmptyString demonstrates a simple tagged type (similar to single-case-union in FP). | |
* - DBConfiguration shows off both union and boolean literal types. | |
* - EnvironmentDBConfigurationMap finishes with a smart fluent builder utilizing Conditional and Mapped types | |
* along with type intersection to create a Fluent Builder with stronger verification than is possible | |
* in C#/Java/C++. | |
* | |
* See the TRY comments for things to... well... try. | |
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Yet another demonstration of TypeScript awesomeness. | |
* | |
* Demonstrates tagged types and template literal strings (v4.1) which allows | |
* * for the type system to infer the literal string type of value | |
* * then deconstruct the literal string type into parts | |
* * in order to parse and validate strings directly in the type system. | |
* | |
* See the TRY comments for things to try. | |
* |
OlderNewer