Types: from TypeScript types to GPU values
TypeShade starts from TypeScript’s type surface, but the final meaning is a GPU value model. Learn the TypeScript idea first: structural typing and type aliases describe value shape. When GPU layout metadata is required, use classes and field decorators.
Start from the TypeScript concept
A type alias gives a name to a value shape. TypeShade keeps that surface, while shader semantics determine which types and expressions are valid in a shader.
1. Use type aliases for plain data
When fields do not need decorators, a type alias is the smallest representation. It is also useful when the same GPU value shape is shared across helper parameters and return values.
type Camera = { view: mat4 pos: vec3}2. A class is a struct and its functions
A TypeShade class is a GPU struct and the functions written with it. The fields are the bytes the host writes. A constructor, a method and a static function each lower to a plain function, so new Ray(o, d) calls Ray_new and r.at(t) calls Ray_at(r, t). Nothing keeps an object alive between them.
class VsIn { position: vec3 uv: vec2}3. Field decorators describe layout
A field takes @location and @builtin, which bind it to the pipeline, and @interpolate, @invariant and @blend_src, which qualify a varying or an output. @align is read and refused, and @size, @offset and @ignore are not attributes the compiler knows. The whole set it accepts is @vertex, @fragment, @compute, @builtin, @location, @interpolate, @invariant, @blend_src and @diagnostic.
class VsOut { @builtin("position") position: vec4 @location(0) uv: vec2}4. Where TypeScript classes stop
- An entry point is a top-level function, not a method.
- A class with no instance fields can be constructed and can have methods, accessors and static members. Its host value is
{}. Reflection includes the internal GPU storage footprint: 4 bytes in std430 and 16 bytes in std140, with no authored field added. - A derived value can be used where its base class is declared when the compiler proves that the base view is read-only and preserves dispatch. Overrides, receiver writes and observable alias mutation require a concrete type or remain unsupported.
- A getter and a setter each lower to a function of their own, and a class has one constructor, as in TypeScript.
newbuilds a value inside a function body, and a module constant takes an object literal.- Prefer a type alias when no field needs a decorator.
5. Concept mapping
| TypeScript | TypeShade |
|---|---|
| type alias / object shape | GPU value shape |
| class fields | GPU struct fields |
| class method | A function taking the struct first |
new | A call of the generated constructor |
extends with super | The base fields spliced in and the body lowered again |
| decorator metadata | GPU layout / stage metadata |
| runtime object | not applicable |
| structural compatibility | applies within shader type checking |
6. Connect the type to an entry point
After defining a struct, use it as an entry point parameter. The value shape and field metadata then define the meaning of that shader input.
class VsIn { @location(0) position: vec3}
@vertexexport function vs(vin: VsIn): vec4 { return vec4(vin.position, 1)}