Max*_*hko 5 architecture domain-driven-design typescript
问题
出于验证目的,我希望在系统的核心中有一些值对象。这些值对象可以是类:
class UserName {
readonly value: string;
constructor(value: string) {
this.value = value.trim();
if (this.value === '') {
throw new Error('Empty value');
}
}
}
// and use it
userService.updateName({id: 1, name: new UserName('Maxim')});
Run Code Online (Sandbox Code Playgroud)
但它效果不佳,因为每个人都可以在不实例化类的情况下调用该服务,因此无需验证:
userService.updateName({id: 1, name: {value: INVALID_NAME});
Run Code Online (Sandbox Code Playgroud)
我的解决方案
我有一个接口和实用函数来创建不方便手动创建的对象:
interface ValueObject<T extends string, U> {
readonly type: T;
readonly value: U;
readonly DO_NOT_CREATE_MANUALLY: 'DO NOT CREATE THIS MANUALLY!',
}
function ValueObject<T extends string, U>(type: T, value: U): ValueObject<T, U> {
return {
type,
value,
DO_NOT_CREATE_MANUALLY: 'DO NOT CREATE THIS MANUALLY!',
};
}
Run Code Online (Sandbox Code Playgroud)
我有一个值对象和实用函数的接口:
interface UserName extends ValueObject<'UserName', string> {}
function UserName(value: string): UserName {
value = value.trim();
if (value === '') {
throw new Error('Empty value');
}
return ValueObject('UserName', value);
}
Run Code Online (Sandbox Code Playgroud)
我这样使用它:
userService.updateName({id: 1, name: UserName('Maxim')});
Run Code Online (Sandbox Code Playgroud)
效果很好。没有人会写:
userService.updateName({
id: 1,
name: {
value: INVALI_VALUE,
type: 'UserName',
DO_NOT_CREATE_MANUALLY: 'DO NOT CREATE THIS MANUALLY!',
},
});
Run Code Online (Sandbox Code Playgroud)
问题
有没有更优雅的方式在打字稿中拥有值对象而不需要DO_NOT_CREATE_MANUALLY?
为了进一步充实@titian 的评论......
考虑下面的类:
class UserName {
public readonly value: string;
constructor(value: string) {
if (value === '') {
throw new Error('Empty value');
}
this.value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
根据Typescript 类型兼容性文档,任何具有属性的对象都value: string将与此类的实例兼容。这就是您想要避免的 - 您想要确保UserName传递给的任何类似对象userService.updateName实际上都是一个UserName对象。
解决方案是向类添加私有属性,以便任何UserName类似对象也必须具有该私有属性:
class UserName {
public readonly value: string;
private readonly is_nominal: boolean = true;
constructor(value: string) {
if (value === '') {
throw new Error('Empty value');
}
this.value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果有人执行以下操作:
userService.updateName({ id: 1, value: { value: 'James T Kirk' } })`
Run Code Online (Sandbox Code Playgroud)
Typescript 会抱怨,因为{ value: 'James T Kirk' }缺少私有is_nominal财产。
然而,有一种更简单(恕我直言,更干净)的方法来添加私有字段:将值设为私有并添加访问器。
class UserName {
private readonly _value: string;
constructor(value: string) {
if (value === '') {
throw new Error('Empty value');
}
this._value = value;
}
get value() { return this._value; }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4938 次 |
| 最近记录: |