一键导入
domain-language-types
Use when naming types. Use when types describe structure not meaning. Use when domain experts won't understand type names.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when naming types. Use when types describe structure not meaning. Use when domain experts won't understand type names.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when defining global types. Use when augmenting window. Use when typing environment variables. Use when working with build-time constants. Use when configuring type definitions.
Use when migrating JavaScript to TypeScript. Use when gradually adopting TypeScript. Use when working with mixed codebases. Use when converting large projects. Use when teams are learning TypeScript.
Use when writing asynchronous code. Use when tempted to use callbacks. Use when composing multiple async operations.
Use when creating types from example data. Use when types don't match all cases. Use when API responses vary.
Use when writing type annotations on variables. Use when TypeScript can infer the type. Use when code feels cluttered with types.
Use when defining array-like types. Use when tempted to use number as index type. Use when understanding array keys.
| name | domain-language-types |
| description | Use when naming types. Use when types describe structure not meaning. Use when domain experts won't understand type names. |
Type names should communicate meaning, not structure.
A type named INodeNameValueData tells you nothing. A type named APIResponse or CustomerOrder tells you everything. Use the language of your business domain, not the language of data structures.
Type names should be meaningful to domain experts.
If a non-programmer can't understand it, rename it.
Remember:
// Bad: describes structure, not meaning
interface IEntityWithIdAndName {
id: string;
name: string;
}
interface IStringPairList {
items: [string, string][];
}
interface IDataRecord {
data: Record<string, unknown>;
}
What IS an IEntityWithIdAndName? A user? A product? A category?
// Good: describes what it IS
interface User {
id: string;
name: string;
}
interface TranslationPairs {
items: [sourcePhrase: string, targetPhrase: string][];
}
interface CustomerProfile {
data: Record<string, unknown>;
}
// Bad: generic/structural names
interface IData {
id: string;
props: Record<string, unknown>;
}
interface IEntity extends IData {
type: string;
}
interface ICollection {
items: IEntity[];
total: number;
}
vs.
// Good: domain language
interface Product {
sku: string;
name: string;
price: Money;
inventory: number;
}
interface Order {
orderNumber: string;
customer: Customer;
items: OrderItem[];
total: Money;
}
interface ProductCatalog {
products: Product[];
totalCount: number;
}
// Bad: I prefix for interfaces
interface IUser { }
interface IProduct { }
// Good: just the name
interface User { }
interface Product { }
// Bad: redundant suffixes
interface UserType { }
interface ProductInterface { }
interface OrderObject { }
// Good: clean names
interface User { }
interface Product { }
interface Order { }
// Bad: generic
interface DataModel { }
interface EntityRecord { }
interface ItemContainer { }
// Good: specific
interface Invoice { }
interface ShippingAddress { }
interface ShoppingCart { }
// Bad: technical property names
interface User {
dataString: string;
valueNumber: number;
itemsArray: Product[];
}
// Good: domain property names
interface User {
email: string;
age: number;
purchases: Product[];
}
Same structure, different domains:
// Healthcare domain
interface Patient {
mrn: string; // Medical Record Number
admissionDate: Date;
diagnosis: string[];
}
// Education domain
interface Student {
studentId: string;
enrollmentDate: Date;
courses: string[];
}
The structure is similar, but the names communicate different meanings.
// OK: widely understood technical terms
interface HttpRequest { }
interface DatabaseConnection { }
interface CacheEntry { }
// OK: truly generic utilities
type Nullable<T> = T | null;
type AsyncResult<T> = Promise<T>;
// OK for internal implementation details
interface InternalCacheNode<T> { }
interface TreeNodeImpl<T> { }
From Domain-Driven Design: use "ubiquitous language" that both developers and domain experts share.
// If domain experts say "fulfillment", use that:
interface OrderFulfillment { }
// Not:
interface OrderProcessingData { }
interface IOrderExecutionEntity { }
Pressure: "Users won't see this type name"
Response: Developers will. Future you will. Make it meaningful.
Action: Name it for what it represents, not how it's structured.
Pressure: "Our style guide says use I prefix"
Response: Conventions should serve clarity, not hinder it.
Action: Challenge conventions that reduce clarity. IUser adds nothing.
| Excuse | Reality |
|---|---|
| "It matches our backend" | Backend might have bad names too |
| "It's just internal" | Internal code needs clarity too |
| "That's our convention" | Bad conventions should change |
// DON'T: Structural/technical names
interface IDataEntity { }
interface StringValuePair { }
interface ItemsCollection<T> { }
// DO: Domain language names
interface Customer { }
interface PriceRange { } // [min: Money, max: Money]
interface ProductCatalog { }
// DON'T: Redundant suffixes
interface UserType { }
interface ProductInterface { }
// DO: Clean names
interface User { }
interface Product { }
Name types for what they mean, not how they're structured.
Domain experts should be able to read your type names and understand what they represent. Invoice tells you more than IFinancialDataRecord. Use the language of your problem domain.
Based on "Effective TypeScript" by Dan Vanderkam, Item 41: Name Types Using the Language of Your Problem Domain.