Foundation

Concept Simplification

Why EvidyTS removes overlapping language choices and keeps one canonical form when possible.

One canonical form when possible

TypeScript and JavaScript often offer several ways to express nearly the same job. That is useful for humans writing by hand, but it also creates branching: the reader or the model has to choose between overlapping constructs before it can focus on the actual domain problem.

Reject duplicated concepts. Keep one strong default when extra variants mainly add decision load.

That is the simplification idea in EvidyTS. The language does not try to remove power for novelty. It tries to remove duplicate or overloaded choices when one canonical form can still do the work. Lower concept count and lower ambiguity leave more attention for user intent, domain modeling, structure, and verification.

Why this helps LLMs

Fewer equally plausible constructs means fewer syntax branches to consider. The model can spend more of its limited working attention on the subject of the code instead of on choosing between several near-duplicate language forms.

Structural simplifications

The clearest examples happen at the project and file level. Ordinary TypeScript is comfortable with free functions, loose constants, extra helper interfaces, and several primary concepts in one file. EvidyTS collapses those options into one main structural path.

Rejected ts
const cache = new Map<string, User>();

function loadUser(id: string): User {
  return new User(id);
}
Allowed ts
export class UserRepository {
  static readonly cache = new Map<string, User>();

  @Spec("Loads a user by id.")
  static loadUser(id: string): User {
    return new User(id);
  }
}

The same idea shows up in type modeling. If you need a pure data contract, prefer a type. If you need shared runtime behavior or overridable methods, use an abstract class. Contracts still matter; the simplification is avoiding interface, type alias, free function, and loose constant patterns all at once when one canonical choice is enough.

Common job Canonical EvidyTS form
Primary runtime behavior class in its own filename-matched file
Pure data shape type
Free helper class method, usually static
Shared top-level constant class property, usually static readonly
Bootstrap action a final top-level new ClassName() only where explicitly allowed

Expression and guardrail simplifications

Some simplifications target overloaded meaning rather than duplicate declarations. JavaScript lets conditions, comparisons, arithmetic, and nullability shortcuts carry several different interpretations. EvidyTS narrows those positions to one explicit reading.

Rejected ts
if (userName) {
  publish();
}

if (status == 0) {
  reset();
}

const delta = "5" - 2;
return user!.name;
Allowed ts
if (userName !== "") {
  publish();
}

if (status === 0) {
  reset();
}

const parsedCount = Number.parseInt("5", 10);
const delta = parsedCount - 2;

if (user === undefined) {
  throw new Error("Expected user");
}

return user.name;

In EvidyTS, boolean positions should mean boolean, arithmetic should mean numeric intent, and nullability claims should be proven in code. This keeps punctuation from carrying hidden proof obligations and makes those positions stable for both humans and models.

Testing-workflow simplifications

Testing gets the same treatment. EvidyTS keeps one companion model for test layouts, host-selection rules, and scenario signatures.

Rejected ts
import { describe, it, expect } from "vitest";

describe("UserService", () => {
  it("loads a user", async () => {
    expect(await loadUser("42")).toBeDefined();
  });
});
Allowed ts
import "./UserService.lll";
import { Scenario, Spec, type ScenarioParameter } from "../../public/lll.lll";

@Spec("Exercises UserService scenarios.")
export class UserServiceTest {
  testType = "unit" as const;

  @Scenario("Loads a user.")
  static async loadsUser(scenario: ScenarioParameter): Promise<void> {
    scenario.assert(true, "Replace with host-class assertion.");
  }
}

This is an intentional narrowing. It gives up some layout freedom so the language, the compiler, and the model all agree on one discoverable way to find tests, name them, run them, and classify them as "unit" or "behavioral".

Not every rule is concept reduction

It would be too broad to claim that every `EvidyTS` restriction exists to remove duplicates. Some rules are there for local reasoning and verification discipline instead.

  • @Spec("...") makes purpose visible before the body begins.
  • Explicit return types make contracts readable from signatures alone.
  • File, method, and folder limits keep complexity density bounded.

These rules complement simplification, but they are better described as boundedness and auditability rules rather than as concept elimination.

Rejected simplifications and boundaries

The simplification bar is stricter than banning syntax because it looks different. A rule earns its place only when one canonical form covers the job without special-case exceptions.

A good example is backticks-only strings. The idea sounds attractive, but static ECMAScript imports still require quoted module specifiers, and TypeScript ambient module declarations do too. That would force exceptions such as:

import "./ClassName.lll";
or
declare module "pkg" 

Once exceptions appear, the rule stops simplifying the language. So EvidyTS rejects that idea and keeps delimiter choice aligned with valid underlying TypeScript and JavaScript syntax.

The broader result

The practical claim is modest but important: when the language removes duplicated concepts and narrows overloaded ones, both humans and models have less syntax branching to manage. That leaves more room for the real work of software: naming the right concepts, giving them stable structure, and verifying behavior through scenarios.