Compare commits

...
2 Commits
Author SHA1 Message Date
zekro 88661ec960 update readme 2026-07-20 09:58:50 +02:00
zekro 1d9a7fa4fe add typestate typescript example 2026-07-20 09:54:35 +02:00
5 changed files with 82 additions and 2 deletions

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
type State = "locked" | "unlocked";
class CredentialManager<S extends State> {
private readonly state?: S;
unlock(this: CredentialManager<"locked">, master_key: string) {
return this as unknown as CredentialManager<"unlocked">;
}
set(this: CredentialManager<"unlocked">, key: string, value: any) {
// ...
}
get(this: CredentialManager<"unlocked">, key: string): string | undefined {
// ...
return undefined;
}
lock(this: CredentialManager<"unlocked">): CredentialManager<"locked"> {
return this as unknown as CredentialManager<"locked">;
}
}
function main2() {
let pw_locked = new CredentialManager<"locked">();
let pw_unlocked = pw_locked.unlock("psst");
pw_unlocked.set("foo", "bar");
let val = pw_unlocked.get("foo");
pw_locked = pw_unlocked.lock();
}
@@ -30,7 +30,7 @@ class WebSocketClient {
}
}
function main_ws() {
function main1() {
const client = new WebSocketClient();
client.send(OpCode.PING, {});
}
@@ -23,7 +23,7 @@ function navigate<P extends string>(path: P, params: ParseUrlParams<P>) {
// ...
}
function main() {
function main3() {
navigate("/hello", {});
navigate("/hello/{name}", { name: "foo" });
navigate("/book/{author}/{id}", { author: "foo", id: "bar" });
+1
View File
@@ -1,2 +1,3 @@
[workspace]
members = ["01-problem", "02-runtime-check", "03-builder-pattern", "04-typestate"]
resolver = "3"
+49
View File
@@ -1,5 +1,54 @@
# Type Level Programming
This repository contains a collection of examples demonstrating various type-level programming patterns in Rust, Go, and TypeScript.
The goal of these examples is to show how to leverage the type system of a language to enforce invariants at compile-time, reducing the need for runtime checks and making the code more robust and self-documenting.
## Repository Structure
The examples are organized by language and complexity.
### Rust
The Rust examples demonstrate a progression of state management for a `CredentialManager`:
- **[01-problem](./01-problem)**: The initial problem where state is not managed, allowing operations in any order.
- **[02-runtime-check](./02-runtime-check)**: Adding runtime checks (e.g., `bool` flags) to ensure operations are performed in the correct state.
- **[03-builder-pattern](./03-builder-pattern)**: Using separate structs to represent different states, ensuring state transitions are enforced at compile-time.
- **[04-typestate](./04-typestate)**: A classic implementation of the Typestate pattern using generics and `PhantomData` to track state.
### Go
- **[05-typestate-go-structs](./05-typestate-go-structs)**: Implementing state transitions in Go using separate structs for each state.
- **[06-typestate-go-interfaces](./06-typestate-go-interfaces)**: Using interfaces to restrict the available methods based on the current state of the object.
### TypeScript
- **[07-typestate-ts](./07-typestate-ts)**: Implementing the Typestate pattern in TypeScript using `this` type parameters to restrict method calls.
- **[08-type-mapping](./08-type-mapping)**: Mapping enum values (like opcodes) to specific argument types for type-safe messaging.
- **[09-type-programming](./09-type-programming)**: Advanced recursive type parsing to extract parameters from URL string literals at compile-time.
## Getting Started
### Rust
You can run the Rust examples using Cargo from the root directory:
```bash
# Example: Running the typestate example
cargo run -p 04-typestate
```
### Go
The Go examples can be run using the Go CLI:
```bash
go run ./05-typestate-go-structs
```
### TypeScript
The TypeScript examples are best viewed in an IDE (like VS Code) to see the type errors and completions. You can also run them using `ts-node`:
```bash
npx ts-node 07-typestate-ts/main.ts
```
## Sources
- https://www.emoses.org/posts/resolver-resolved-pattern/