Principle | Description |
---|---|
Readability First | Code should be written with the next developer in mind |
Consistency Matters | Follow established patterns throughout the project |
Self-Explanatory Code | Write intuitive code that requires minimal comments |
Comprehensive Documentation | Document following InSpatial Doc Rules |
Standard | Description | Guidelines |
---|---|---|
📦 ESM Modules | Use ECMAScript Modules exclusively | • Avoid CommonJS modules • Use import/export syntax |
🔒 Deno APIs | Prefer Deno over Node.js APIs | • Use provided Deno API abstractions • Follow secure practices |
📝 File Names | Cross-platform compatible naming | • Avoid * , : , ? • No case-only differences • Use kebab-case |
⚡ Type Performance | Avoid "slow types" | • Follow JSR slow types guide • Use efficient type patterns • Follow Typescript's Performance Rules |
🚫 Dependencies | No native binary dependencies | • Pure TypeScript preferred • Use WASM for native functionality |
Category | Guidelines | Tools & Resources |
---|---|---|
🎨 Shaders | • Use WGSL or TSL • WebGL 2.0 compatibility |
@inspatial/util |
🔄 Programming Patterns | • Functional programming • Declarative patterns |
Patterns.dev |
✍️ Variable Naming | • Use auxiliary verbs • Self-documenting names |
Examples:isLoading hasError |
📁 File Structure | 1. Exported components 2. Subcomponents 3. Helpers 4. Static content 5. Types |
Keep consistent order |
Tool | Purpose | Usage |
---|---|---|
InSpatial Kit | Component Construction | Primary UI building blocks |
InSpatial ISS | Styling | Styling system |
InSpatial Util | Utilities | Common utilities |
InSpatial Infetch | HTTP Requests | API communication |
Motion | Animations | JavaScript animations & transitions |
Type | Convention | Example | Additional Rules |
---|---|---|---|
Variables | camelCase | userData |
Use descriptive names that convey intent |
Components | PascalCase | UserProfile |
- |
Files/Directories | kebab-case | user-profile.ts |
- |
Types/Interfaces | PascalCase + Prop | UserProp |
Must start with uppercase letter |
Private Variables | underscore prefix | _privateData |
- |
Functions | camelCase | fetchUserData |
- |
Constants | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
- |
Boolean Variables | camelCase with prefix | isLoading , hasError |
Use prefixes: is, has, should, can, etc. |
Event Handlers | camelCase with 'handle' prefix | handleClick |
- |
- Avoid abbreviations unless widely understood (e.g.,
id
is fine, butusr
is not) - Names should be self-documenting and clearly indicate purpose
- Keep naming consistent across related entities
Practice | Do | Don't | Reason |
---|---|---|---|
Type Annotations | function foo(): BazType |
function foo() |
Helps compiler work faster with explicit types |
Type Composition | interface Foo extends Bar, Baz |
type Foo = Bar & Baz |
Interfaces create cached, flat object types |
Base Types | interface Animal { ... } |
type Animal = Dog | Cat |
Reduces type comparison complexity |
Complex Types | type ComplexType = { ... } |
Inline complex types | Named types are more compact and cacheable |
Flag | Purpose | Impact |
---|---|---|
--incremental |
Save compilation state | Recompiles only changed files |
--skipLibCheck |
Skip .d.ts checking |
Faster compilation by skipping verified types |
--strictFunctionTypes |
Optimize type checks | Reduces assignability checks between types |
- Use explicit return types on exported functions
- Prefer interfaces over type intersections for better caching
- Name complex types instead of using anonymous types
- Use base types instead of large union types
- Keep type hierarchies shallow when possible
- Use ES6+ syntax: arrow functions, destructuring, template literals, etc.
- Avoid
any
unless absolutely necessary. Use strict and explicit typing. - Follow Typescript's Performance Rules
// ✅ Do: Use interfaces and explicit types
interface UserData {
id: string;
name: string;
}
// ✅ Do: Use ES6+ syntax with strict typing
function fetchUser(id: string): Promise<UserData> {
return inFetch(`/users/${id}`);
}
// ❌ Don't: Use type intersections and implicit types
type UserData = BaseUser & {
extraData: unknown;
}
// ❌ Don't: Use type intersections and implicit types
function fetchUser(id) {
return inFetch(`/users/${id}`);
}
- Use InSpatial Test for all types of tests
- Place tests next to the relevant file
- Use one of these naming patterns:
file.test.ts
(preferred)file_test.ts
- Write meaningful test descriptions and cover edge cases
- Check test coverage using
deno test --coverage
- Follow InSpatial Test Rules.
# Run all tests
deno test
# Run specific test suite
deno test packages/core
# Run with coverage
deno test --coverage
import { test } from "@inspatial/test";
// Prefer object style for tests
// ✅ Do: Descriptive test names and comprehensive test cases
test({
name: "Button renders with correct label",
fn: () => {
const user = await fetchUser('123');
expect(user).toHaveProperty('id', '123');
}
});
describe('fetchUser', () => {
it('returns a user object when the request is successful', async () => {
const user = await fetchUser('123');
expect(user).toHaveProperty('id', '123');
});
it('throws an error when the user ID is invalid', async () => {
await expect(fetchUser('')).rejects.toThrow('Invalid user ID');
});
});
// ❌ Don't: Vague test names or incomplete coverage
test({
name: "button test",
fn: () => {
// ...
}
});
- When to Comment:
- Use comments to explain why, not what.
The code should already explain what it does. - Document complex logic or unusual decisions.
- Use comments to explain why, not what.
Example:
/**
* Fetches a user by ID from the server.
*
* @param id - The ID of the user to fetch.
* @returns A promise resolving to the user object.
*/
function fetchUser(id: string): Promise<User> {
return inFetch(`/users/${id}`);
}