mcpField
D
domain-language-types

domain-language-types

github.com/marius-townhouse开发645 次安装39 周前更新
代码仓库

关于 domain-language-types

一项 TypeScript 开发技能,指导开发者使用问题领域的概念命名类型,让领域专家也能理解类型所代表的含义。

主要功能

  1. 01使用领域语言命名类型
  2. 02将结构化名称改为有意义的名称
  3. 03避免匈牙利命名法前缀和冗余后缀
  4. 04采用领域专家共用的术语

适用场景

  1. 01为新功能命名类型
  2. 02重构含义不清的类型名称
  3. 03与领域专家一起评审 API

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill domain-language-types

安装后在 Claude Code 中输入/domain-language-types确认已加载。

详细介绍

使用问题领域的语言为类型命名

概述

类型名称应该传达含义,而不是结构。

名为 INodeNameValueData 的类型毫无信息量。名为 APIResponse 或 CustomerOrder 的类型则能说明一切。使用业务领域的语言,而不是数据结构的语言。

何时使用这项技能

  • 为新类型命名
  • 重构含义不清的类型名称
  • 与领域专家一起审查代码
  • 设计公共 API

铁律

Type names should be meaningful to domain experts.
If a non-programmer can't understand it, rename it.

请记住:

  • 业务术语 > 技术术语
  • 含义 > 结构
  • 名称就是文档
  • 领域专家应该能认出这些类型

检测:结构化名称

// Bad: describes structure, not meaning
interface IEntityWithIdAndName {
  id: string;
  name: string;
}

interface IStringPairList {
  items: [string, string][];
}

interface IDataRecord {
  data: Record<string, unknown>;
}

IEntityWithIdAndName 到底是什么?用户?产品?类别?

更好的做法:领域名称

// 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;
}

对比:

// 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[];
}

上下文很重要

相同的结构,不同的领域:

// Healthcare domain
interface Patient {
  mrn: string;          // Medical Record Number
  admissionDate: Date;
  diagnosis: string[];
}

// Education domain  
interface Student {
  studentId: string;
  enrollmentDate: Date;
  courses: string[];
}

结构相似,但名称传达的含义不同。

技术名称也适用的情况

标准技术概念
// 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> { }

通用语言

领域驱动设计要求使用开发人员和领域专家共同理解的“通用语言”。

// If domain experts say "fulfillment", use that:
interface OrderFulfillment { }

// Not:
interface OrderProcessingData { }
interface IOrderExecutionEntity { }

抵御压力的方案

1. “这是技术细节”

压力:“用户不会看到这个类型名称”

**回应:**开发人员会看到。未来的你也会看到。让它有明确含义。

**行动:**根据它代表什么来命名,而不是根据它的结构来命名。

2. “我们有命名规范”

压力:“我们的风格指南要求使用 I 前缀”

**回应:**规范应该提升清晰度,而不是妨碍清晰度。

**行动:**质疑那些降低清晰度的规范。IUser 没有任何增益。

危险信号——停下来重新考虑

  • 类型名称以 I、T 开头,或以 Type/Interface/Object 结尾
  • 描述结构的名称(StringArray、NumberMap)
  • 领域专家无法识别的名称
  • 多个都可以称为“Data”的类型

常见的自我辩解(都不成立)

借口事实
“它和我们的后端一致”后端也可能有糟糕的名称
“这只是内部代码”内部代码也需要清晰
“这是我们的规范”糟糕的规范应该改变

快速参考

// 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 { }

总结

根据类型的含义命名,而不是根据它的结构命名。

领域专家应该能通过类型名称理解它们代表什么。Invoice 比 IFinancialDataRecord 说明的信息更多。使用问题领域的语言。

参考资料

基于 Dan Vanderkam 的《Effective TypeScript》第 41 条:使用问题领域的语言为类型命名。

评论

支持 Markdown