TypeScript/fp-ts 中 Either 的类型错误
Type error with Either in TypeScript/fp-ts
我正在使用 fp-ts,我有一个函数 returns 一个 HttpError 对象或一个字符串:
async getPreferencesForUserId(userId: string): Promise<Either<HttpResponseNotFound, string>> {
const preferences = await getRepository(Preference).findOne({ userId });
return preferences ? right(preferences.preferenceMap) : left(new HttpResponseNotFound({ code: 404, message: 'Could not find preferences' }));
}
我想像这样在另一个文件中调用这个函数:
const preferenceMapAsJsonStringOrError: Either<HttpResponseNotFound, string> = await this.preferenceService.getPreferencesForUserId(userId);
const response: HttpResponseOK | HttpResponseNotFound = pipe(preferenceMapAsJsonStringOrError, fold(
e => e,
r => new HttpResponseOK(r)
));
response.setHeader('content-type', 'application/json');
return response;
这基本上就是我在 Scala 中的做法。 (除了 fold
是 Either 类型上的一个方法,而不是一个独立的函数——所以我在这里使用 pipe
助手)
问题是,我收到来自 ts-server 的错误:
Type 'HttpResponseOK' is missing the following properties from type 'HttpResponseNotFound': isHttpResponseNotFound, isHttpResponseClientError
和
node_modules/fp-ts/lib/Either.d.ts:129:69
129 export declare function fold<E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B): (ma: Either<E, A>) => B;
~~~~~~~~~~~
The expected type comes from the return type of this signature.
我可以通过更命令的方式解决这个问题:
const preferenceMapAsJsonStringOrError: Either<HttpResponseNotFound, string> = await this.preferenceService.getPreferencesForUserId(userId);
if (isLeft(preferenceMapAsJsonStringOrError)) {
return preferenceMapAsJsonStringOrError.left;
}
const response = new HttpResponseOK(preferenceMapAsJsonStringOrError.right);
response.setHeader('content-type', 'application/json');
return response;
但那时我几乎失去了使用 Either 的好处。
问题是,考虑到 TS 推理的工作原理,当使用 fold
时,其 return 类型是 "fixed" 到第一个参数之一 (onLeft
), onRight
无法 "widen" 它 HttpResponseNotFound | HttpResponseOK
.
换句话说,一般情况下使用TS和fp-ts是不会免费统一的
对于这种特定情况,我建议
- 为输出中想要的联合类型命名(并非绝对必要,但有助于阐明意图):
type HttpResponse = HttpResponseNotFound | HttpResponseOK
- 明确地 "widen" return 类型的折叠。这必须手动完成,或者通过注释
onLeft
fold
参数的 return 类型:
const response: HttpResponse = pipe(
preferenceMapAsJsonStringOrError,
E.fold((e): HttpResponse => e, r => new HttpResponseOK(r))
)
或者定义一个 widen
助手如下:
const widen = E.mapLeft<HttpResponse, HttpResponse>(e => e);
const response: HttpResponse = pipe(
preferenceMapAsJsonStringOrError,
widen,
E.fold(identity, r => new HttpResponseOK(r))
);
希望这对您有所帮助:)
尝试这两种方法后,我仍然遇到类型错误。为我修复它的是明确指定折叠的类型。
fold<HttpResponseNotFound, HttpResponseOK, HttpResponseNotFound | HttpResponseOK>(
e => e,
r => new HttpResponseOK(r)
)
我正在使用 fp-ts,我有一个函数 returns 一个 HttpError 对象或一个字符串:
async getPreferencesForUserId(userId: string): Promise<Either<HttpResponseNotFound, string>> {
const preferences = await getRepository(Preference).findOne({ userId });
return preferences ? right(preferences.preferenceMap) : left(new HttpResponseNotFound({ code: 404, message: 'Could not find preferences' }));
}
我想像这样在另一个文件中调用这个函数:
const preferenceMapAsJsonStringOrError: Either<HttpResponseNotFound, string> = await this.preferenceService.getPreferencesForUserId(userId);
const response: HttpResponseOK | HttpResponseNotFound = pipe(preferenceMapAsJsonStringOrError, fold(
e => e,
r => new HttpResponseOK(r)
));
response.setHeader('content-type', 'application/json');
return response;
这基本上就是我在 Scala 中的做法。 (除了 fold
是 Either 类型上的一个方法,而不是一个独立的函数——所以我在这里使用 pipe
助手)
问题是,我收到来自 ts-server 的错误:
Type 'HttpResponseOK' is missing the following properties from type 'HttpResponseNotFound': isHttpResponseNotFound, isHttpResponseClientError
和
node_modules/fp-ts/lib/Either.d.ts:129:69
129 export declare function fold<E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B): (ma: Either<E, A>) => B;
~~~~~~~~~~~
The expected type comes from the return type of this signature.
我可以通过更命令的方式解决这个问题:
const preferenceMapAsJsonStringOrError: Either<HttpResponseNotFound, string> = await this.preferenceService.getPreferencesForUserId(userId);
if (isLeft(preferenceMapAsJsonStringOrError)) {
return preferenceMapAsJsonStringOrError.left;
}
const response = new HttpResponseOK(preferenceMapAsJsonStringOrError.right);
response.setHeader('content-type', 'application/json');
return response;
但那时我几乎失去了使用 Either 的好处。
问题是,考虑到 TS 推理的工作原理,当使用 fold
时,其 return 类型是 "fixed" 到第一个参数之一 (onLeft
), onRight
无法 "widen" 它 HttpResponseNotFound | HttpResponseOK
.
换句话说,一般情况下使用TS和fp-ts是不会免费统一的
对于这种特定情况,我建议
- 为输出中想要的联合类型命名(并非绝对必要,但有助于阐明意图):
type HttpResponse = HttpResponseNotFound | HttpResponseOK
- 明确地 "widen" return 类型的折叠。这必须手动完成,或者通过注释
onLeft
fold
参数的 return 类型:
const response: HttpResponse = pipe(
preferenceMapAsJsonStringOrError,
E.fold((e): HttpResponse => e, r => new HttpResponseOK(r))
)
或者定义一个 widen
助手如下:
const widen = E.mapLeft<HttpResponse, HttpResponse>(e => e);
const response: HttpResponse = pipe(
preferenceMapAsJsonStringOrError,
widen,
E.fold(identity, r => new HttpResponseOK(r))
);
希望这对您有所帮助:)
尝试这两种方法后,我仍然遇到类型错误。为我修复它的是明确指定折叠的类型。
fold<HttpResponseNotFound, HttpResponseOK, HttpResponseNotFound | HttpResponseOK>(
e => e,
r => new HttpResponseOK(r)
)