您好,我正在尝试使用ddd,但是在对映射器进行建模以在使用ts对数据库进行操作后返回域的实例时遇到了问题:
这是我的网域:
export interface ILocationProps {
stret_address: string;
cep_code: CepCode;
}
export class LocationSeats extends AggregateRoot<ILocationProps> {
get StretAddress(): string {
return this.props.stret_address;
}
get CepCode(): CepCode {
return this.props.cep_code;
}
private constructor(props: ILocationProps, id?: UniqueEntityID) {
super(props, id);
}
public static create(
props: ILocationProps,
id?: UniqueEntityID,
): Result<LocationSeats> {
const guardedProps = [
{ argument: props.cep_code, argumentName: 'cep_code' },
{ argument: props.stret_address, argumentName: 'stret_address' },
];
const guardResult = Guard.againstNullOrUndefinedBulk(guardedProps);
if (!guardResult.succeeded) {
return Result.fail<LocationSeats>(guardResult.message);
}
const location = new LocationSeats(props, id);
const idWasProvided = !!id;
if (!idWasProvided) {
location.when(new LocationCreatedEvent(location));
}
return Result.ok<LocationSeats>(location);
}
}
这是我的映射器:
export default interface IMapperr<T> {
toPersistence(t: any): Result<T>;
toDomain(raw: any): Result<T>;
}
@singleton()
export class LocationMapper<Location = LocationSeats> implements IMapper<Location> {
constructor() {}
public toPersistence(t: any) {
throw new Error('Method not implemented.');
}
private validate() {}
public toDomain(raw: any): Result<Location> {
const cepCodeorError = CepCode.create(raw.cep_code);
const locationOrError = LocationSeats.create(
{
cep_code: cepCodeorError.getValue(),
stret_address: raw.street_address,
},
new UniqueEntityID(raw.id),
);
return locationOrError;
}
}
这是我的结果类:
export class Result<T> {
public isSuccess: boolean;
public isFailure: boolean;
public error?: T | string;
private _value?: T;
constructor(isSuccess: boolean, error?: T | string, value?: T) {
if (isSuccess && error) {
throw new Error(
'InvalidOperation: A result cannot be successful and contain an error',
);
}
if (!isSuccess && !error) {
throw new Error(
'InvalidOperation: A failing result needs to contain an error message',
);
}
this.isSuccess = isSuccess;
this.isFailure = !isSuccess;
this.error = error;
this._value = value;
Object.freeze(this);
}
getValue(): T {
if (!this.isSuccess) {
console.log(this.error);
throw new Error(
"Can't get the value of an error result. Use 'errorValue' instead.",
);
}
if (!this._value)
throw new Error(
"Can't get the value of an error result. Use 'errorValue' instead.",
);
return this._value;
}
errorValue(): T {
return this.error as T;
}
static ok<U>(value?: U): Result<U> {
return new Result<U>(true, undefined, value);
}
static fail<U>(error: any): Result<U> {
return new Result<U>(false, error);
}
static combine(results: Result<any>[]): Result<any> {
for (const result of results) {
if (result.isFailure) return result;
}
return Result.ok();
}
}
但是我得到了这个错误:
在我的toDomain函数上:
public toDomain(raw: any): Result<Location> {
const cepCodeorError = CepCode.create(raw.cep_code);
const locationOrError = LocationSeats.create(
{
cep_code: cepCodeorError.getValue(),
stret_address: raw.street_address,
},
new UniqueEntityID(raw.id),
);
return locationOrError;
}
错误:
Type 'Result<LocationSeats>' is not assignable to type 'Result<Location>'.
Type 'LocationSeats' is not assignable to type 'Location'.
'Location' could be instantiated with an arbitrary type which could be unrelated to 'LocationSeats'.ts(2322)
我不知道为什么我的create函数返回一个类型:结果
答案 0 :(得分:1)
问题是您已将toDomain
标记为返回Location
,这是没有约束的模板参数,但是您已经对其进行硬编码以返回LocationSeats.create
。 Typescript不知道LocationSeats.create
是否与您可能选择为Location
传递的任何通用类型兼容。
在设计要构造的类型上通用的工厂功能的问题经常使刚接触Typescript的人绊倒。原因通常是,与某些其他语言不同,通用类型参数不能用作运行时对象,在运行时对象上可以调用诸如create
方法之类的静态方法。它们会在运行时被完全擦除。
在Typescript中,要创建通用工厂,您实际上必须在运行时将构造函数引用传递给工厂。
类似这样的事情可能与您想要的东西很接近(将其略微缩小以显示我要突出显示的部分):
class LocationSeats extends AggregateRoot<ILocationProps> {
private constructor (props: ILocationProps, id?: UniqueEntityID) {
super(props, id)
}
static create (props: ILocationProps, id?: UniqueEntityID): Result<LocationSeats> {
return Result.ok(new LocationSeats(props, id))
}
}
// We need an explicit factory interface for creating these objects
interface LocationCreator<T> {
create (props: ILocationProps, id?: UniqueEntityID): Result<T>
}
class LocationMapper<Location> {
// Need to accept the Location creator at runtime (Location is inferred)
constructor (private creator: LocationCreator<Location>) {}
toDomain (): Result<Location> {
return this.creator.create({
cep_code: '',
stret_address: '',
})
}
}
// Need to pass the LocationSeats constructor in at runtime
const mapper = new LocationMapper(LocationSeats)