TypeScript中如何优雅定义带默认值的配置模型?
TypeScript 中带默认值的数据类实现方案
在TypeScript里,想要实现类似Python dataclass或Pydantic的「以数据为中心、带默认值和可选验证」的类,有几种优雅的方案,以下是具体实现:
1. 使用类(Class)实现(最接近Python风格)
直接通过类定义属性、默认值,还能附加验证逻辑,结构和Python的dataclass最相似:
class User { id: number; name: string; friends: number[]; constructor(props: { id: number; name?: string; friends?: number[] }) { this.id = props.id; // 使用空值合并运算符填充默认值 this.name = props.name ?? 'John Doe'; this.friends = props.friends ?? []; } // 可选:添加字段验证逻辑 validate(): void { if (this.name.length < 2) { throw new Error('用户名长度不能小于2'); } if (this.id <= 0) { throw new Error('用户ID必须为正整数'); } } } // 使用示例 const user1 = new User({ id: 1 }); console.log(user1.name); // 输出 'John Doe' const user2 = new User({ id: 2, name: 'Alice', friends: [3, 4] }); user2.validate(); // 验证通过
2. 工厂函数 + TypeScript工具类型(轻量纯数据方案)
通过工具类型区分「必填字段」和「带默认值的可选字段」,避免重复定义类型,同时保证返回值的字段完整性:
// 定义完整的用户类型(所有字段均为必填) type User = { id: number; name: string; friends: number[]; }; // 定义工厂函数的参数类型:必填id,其余字段可选 type UserCreateProps = Partial<Pick<User, 'name' | 'friends'>> & Pick<User, 'id'>; // 工厂函数:填充默认值并返回完整User类型 function createUser(props: UserCreateProps): User { const defaults: Pick<User, 'name' | 'friends'> = { name: 'John Doe', friends: [] }; return { ...defaults, ...props }; } // 使用示例 const user = createUser({ id: 1 }); console.log(user.name); // 输出 'John Doe' // TypeScript会强制校验:必须传入id,返回的user中name、friends均为必填字段
3. Zod 方案(验证+类型生成一体化)
你提到Zod侧重于未知数据验证,但其实它完全支持定义带默认值的Schema,并自动推导完整类型,无需重复定义:
import { z } from 'zod'; // 定义Schema,同时指定默认值和验证规则 const UserSchema = z.object({ id: z.number().positive('用户ID必须为正整数'), name: z.string().min(2).default('John Doe'), friends: z.array(z.number()).default([]) }); // 自动推导完整的User类型 type User = z.infer<typeof UserSchema>; // 使用示例 // 仅传入必填的id,其余字段自动填充默认值 const user = UserSchema.parse({ id: 1 }); console.log(user.name); // 输出 'John Doe' // 如果传入不符合规则的数据会自动抛出错误 // UserSchema.parse({ id: -1 }); // 抛出错误:用户ID必须为正整数
方案对比
- 类方案:适合需要附加业务方法(如验证)、偏向OOP风格的场景,最贴近Python dataclass的使用体验。
- 工厂函数方案:轻量灵活,适合纯数据结构场景,无类的额外开销。
- Zod方案:适合需要严格数据校验(如处理API输入、表单数据)的场景,默认值与类型定义统一在Schema中,避免重复编写。
内容的提问来源于stack exchange,提问作者Trondh
相关产品推荐
相关产品推荐

