TyForge
Português

Type-safe schema validation, Result pattern and DDD building blocks for TypeScript.
Zero boilerplate — install, import, use. Every validation, every naming convention, every architectural pattern already exists in TyForge. You write domain logic, not infrastructure.
Why TyForge?
For humans: standardized code, zero debate
TyForge eliminates one of the biggest hidden costs in software teams: deciding how to do things.
Every project that adopts TyForge speaks the same language — same prefixes, same conventions, same validation flow and error handling. A developer familiar with TyForge can open any project based on it and quickly understand the entire structure.
This goes beyond aesthetics. When validation, naming, domain rules, and error handling are already built into the framework, developers stop writing repetitive code and focus exclusively on business logic.
The gain is cumulative:
- Faster onboarding
- More objective code reviews
- Fewer inconsistencies
- Safer refactoring
Because every project follows the exact same mental model.
For AI: less ambiguity, better results
AI coding assistants work best when the environment is predictable. TyForge provides exactly that: a closed set of patterns, rules, and structures that eliminate ambiguity.
Instead of inferring conventions, the AI follows a system already defined — and validated by the code itself.
In practice, this results in:
- High first-try accuracy — generated code tends to compile and pass validations without adjustments, thanks to the type system and linter constraints
- Consistent output — regardless of model or session, the structure generated for Entities, UseCases, and TypeFields follows the same pattern
- Automatic self-correction — errors are quickly caught by
tsc and tyforge-lint, reducing manual iteration
- Safe composition — AI can build complex models by combining TypeFields, schemas, and domain events without relying on global context
The result: less trial and error, more usable code from the first generation.
TyForge provides the structure. AI provides the speed.
Full-stack: one single source of truth
TyForge runs anywhere TypeScript runs — Node.js, Deno, Bun, Angular, React, Vue, Next.js, React Native, Electron. The same TypeFields that validate input on your API validate forms on your UI.
This means:
- Validations don't need to be rewritten
- Formatting doesn't diverge between client and server
- Business rules aren't scattered
A single schema definition becomes the source of truth for the entire stack.
TyForge centralizes the rules. Both sides just consume.
Installation
npm install tyforge
Quick Start
Schema validation with automatic type inference
import { SchemaBuilder, FString, FEmail, FInt, isSuccess } from "tyforge";
import type { ISchema, InferProps, InferJson } from "tyforge";
const userSchema = {
name: { type: FString },
email: { type: FEmail },
age: { type: FInt, required: false },
} satisfies ISchema;
type TUserJson = InferJson<typeof userSchema>;
type TUserProps = InferProps<typeof userSchema>;
const validator = SchemaBuilder.compile(userSchema);
const result = validator.create({ name: "Maria Silva", email: "maria@navegar.com" });
if (isSuccess(result)) {
result.value.name.getValue();
result.value.email.getValue();
}
Result pattern — functional error handling
import { ok, err, isSuccess, isFailure } from "tyforge";
import type { Result } from "tyforge";
function divide(a: number, b: number): Result<number, Error> {
if (b === 0) return err(new Error("Division by zero"));
return ok(a / b);
}
const result = divide(10, 2)
.map(v => v * 100)
.flatMap(v => divide(v, 5))
.fold(
value => `Result: ${value}`,
error => `Error: ${error.message}`,
);
TypeFields — validated Value Objects
import { FEmail, FDocumentCpf, FCurrency, FPassword, TypeField } from "tyforge";
const email = FEmail.createOrThrow("user@company.com");
email.getValue();
email.formatted();
const cpf = FDocumentCpf.createOrThrow("52998224725");
cpf.formatted();
const pwd = FPassword.createOrThrow("S3cur3!Pass");
TypeField.configure({ localeDisplay: "br" });
const price = FCurrency.createOrThrow(1234.50);
price.getValue();
price.toDecimalValue();
price.formatted();
Money arithmetic — zero floating point issues
import { FMoney, FCurrency } from "tyforge";
const a = FCurrency.createOrThrow(0.1);
const b = FCurrency.createOrThrow(0.2);
const sum = a.add(b);
const price = FMoney.createOrThrow(1050);
price.toDecimal();
price.isPositive();
price.isZero();
const discount = FMoney.createOrThrow(200);
const final = price.subtract(discount);
Domain Models — Entity, Aggregate, Domain Events
import { SchemaBuilder, FId, FString, FEmail, ok, isFailure } from "tyforge";
import { Aggregate, DomainEvent } from "tyforge";
import type { ISchema, InferProps, InferJson } from "tyforge";
const userSchema = {
id: { type: FId, required: false },
name: { type: FString },
email: { type: FEmail },
} satisfies ISchema;
type TUserProps = InferProps<typeof userSchema>;
type TUserJson = InferJson<typeof userSchema>;
class EventUserCreated extends DomainEvent<{ userId: string; email: string }> {
readonly queueName = "user-events";
static create(userId: string, email: string): EventUserCreated {
return new EventUserCreated("user.created", { userId, email });
}
}
class User extends Aggregate<TUserProps, TUserJson> implements TUserProps {
readonly id: FId | undefined;
readonly name: FString;
readonly email: FEmail;
protected readonly _classInfo = { name: "User", version: "1.0.0", description: "User aggregate" };
private constructor(props: TUserProps) {
super();
this.id = props.id;
this.name = props.name;
this.email = props.email;
}
static create(data: TUserJson) {
const validator = SchemaBuilder.compile(userSchema);
const result = validator.create(data);
if (isFailure(result)) return result;
const user = new User(result.value);
const id = user.id?.getValue() ?? FId.generateId();
user.addDomainEvent(EventUserCreated.create(id, user.email.getValue()));
return ok(user);
}
}
Expose / Redaction — control JSON output
const schema = {
name: { type: FString },
email: { type: FEmail, expose: "private" },
password: { type: FPassword, expose: "redacted" },
} satisfies ISchema;
Locale system — display + region + data, independently configured
import { TypeField, FBankCode, FCurrency, FDocumentCpf } from "tyforge";
TypeField.configure({ localeDisplay: "br", localeRegion: "br", localeData: "br" });
FBankCode.createOrThrow("60701190");
FCurrency.createOrThrow(1234.50).formatted();
FCurrency.createOrThrow(1234.50).formatted("data");
Form input normalization
import { FCurrency, FInt } from "tyforge";
FCurrency.formCreate("1234,50");
FInt.formCreate("42");
FInt.formCreate("0x1A");
FInt.formCreate("1e5");
Batch validation with parallel workers
import { SchemaBuilder, FString, FEmail, batchCreate } from "tyforge";
import type { ISchema } from "tyforge";
const schema = {
name: { type: FString },
email: { type: FEmail },
} satisfies ISchema;
const items = Array.from({ length: 10000 }, (_, i) => ({
name: `User ${i}`,
email: `user${i}@company.com`,
}));
const result = await batchCreate(schema, items);
const result = await batchCreate(schema, items, { concurrency: 4 });
Exceptions — RFC 7807 with lazy stack trace
import { ExceptionValidation, ExceptionBusiness, ExceptionNotFound, OHttpStatus } from "tyforge";
const err = ExceptionValidation.create("email", "Invalid email format");
err.status;
err.toJSON();
Nested schemas and arrays
const orderSchema = {
id: { type: FId },
address: {
street: { type: FString },
city: { type: FString },
state: { type: FStateCode },
},
items: [{
type: {
productId: { type: FId },
quantity: { type: FInt },
price: { type: FMoney },
},
}],
} satisfies ISchema;
Linter — enforces conventions automatically
npx tyforge-lint
npx tyforge-lint --staged
npx tyforge-lint --fix
npx tyforge-lint --init
10 rules: no-any, no-cast, no-non-null, no-ts-ignore, no-export-default, no-to-json-lowercase, no-new-type-field, no-magic-http-status, no-declare, no-satisfies-without-prefix.
Modules
| Result Pattern | ok(), err(), map, flatMap, fold, match, all, allSettled, toPromise — functional error handling with zero exceptions |
| Schema Builder | Compiled schema validation with InferProps/InferJson type inference, nested objects, arrays, batchCreate, composeSchema |
| Type Fields | Validator Value Objects — strings, emails, currency, banking, documents, PIX, security, enums, dates, identifiers |
| Domain Models | Entity, ValueObject, Aggregate (with domain events), Dto, DtoReq, DtoRes — full DDD building blocks |
| Exceptions | RFC 7807 exception types with lazy stack trace and OHttpStatus constants |
| Application | UseCase, IMapper, Saga, DomainEventDispatcher, CQRS interfaces |
| Infrastructure | Repository, RepositoryRead, RepositoryWrite, RepositoryCrud, Paginated, ServiceBase, IUnitOfWork, IOutbox |
| HTTP Client | ServiceHttp abstract base class — secure HTTP client with Result pattern, SSRF/CRLF/path traversal protection, timeout, ExceptionHttp |
| GraphQL Client | ServiceGraphQL abstract base class — secure GraphQL client with Result pattern, introspection blocking, prototype pollution protection, UNAUTHENTICATED detection, ExceptionGraphQL |
| WebSocket Client | ServiceWebSocket abstract base class — WebSocket client with connect/disconnect/send/subscribe, reconnect with jitter and delay cap, DNS rebinding protection, ExceptionWebSocket |
| Tools | TypeGuard, ToolObjectTransform (flatten/unflatten), ToolCliParser, ToolFileDiscovery, ToolGit, ToolNetworkSecurity |
| Linter | npx tyforge-lint — 10 rules with --init / --fix / --format json for CI |
| Config | tyforge.config.json — global validation levels (full, type, none) and linter settings |
Type Fields by Category
| Strings | FString, FText, FDescription, FFullName, FBusinessName, FEmail |
| Numeric | FInt, FFloat |
| Pagination | FPageNumber, FPageSize, FSortOrder |
| Currency | FMoney (integer cents), FCurrency (decimal convenience) — arithmetic, comparisons, fromDecimal() |
| Dates | FDate, FDateISODate, FDateTimeISOZ, FDateTimeISOZMillis, FDateISOCompact, FDateTimeISOCompact, FDateTimeISOFullCompact |
| Identifiers | FId, FIdReq, FTransactionId, FDeviceId, FCorrelationId, FReconciliationId, FIdempotencyKey, FCertificateThumbprint |
| Documents | FDocumentCpf, FDocumentCnpj, FDocumentCpfOrCnpj, FDocumentRg, FDocumentId, FDocumentType, FDocumentStateRegistration, FDocumentMunicipalRegistration |
| Banking | FBankCode, FBankBranch, FBankAccountNumber, FBankNsu, FBankE2eId, FEmvQrCodePayload |
| PIX | FPixKey, FPixKeyType |
| Security | FApiKey, FBearer, FPassword, FSignature, FPublicKeyPem, FTotpCode, FTotpSecret, FHashAlgorithm |
| HTTP | FHttpMethod, FHttpFormat, FHttpStatus |
| GraphQL | FGraphQLDocument, FGraphQLOperationName, FFetchPolicy |
| URL | FUrlOrigin, FUrlFull, FUrlPath, FUrlDns, FUrlQuery |
| Enums | FAppStatus, FBoolInt, FPersonType, FGender, FMaritalStatus, FTransactionStatus, FStateCode |
| Other | FBoolean, FJson, FTraceId |
Subpath Exports
import { ok, err } from "tyforge/result";
import { FString, FEmail } from "tyforge/type-fields";
import { ExceptionValidation } from "tyforge/exceptions";
import { SchemaBuilder } from "tyforge/schema";
import { TypeGuard } from "tyforge/tools";
import { ServiceHttp, ExceptionHttp } from "tyforge/http";
import { ServiceGraphQL, ExceptionGraphQL } from "tyforge/graphql";
Documentation
Full documentation at tyforge.navegarsistemas.com.br.
License
MIT - Navegar Sistemas