I try to replicate this code from this blog, but running into some pretty obscure errors
import { option, identity, apply } from 'fp-ts';
import type { Kind, URIS } from 'fp-ts/HKT';
import { pipe } from 'fp-ts/lib/function';
type OrderId = string;
type OrderState = 'active' | 'deleted';
interface User {
readonly name: string;
readonly isActive: boolean;
}
interface OrderHKD<F extends URIS> {
readonly id: Kind<F, OrderId>;
readonly issuer: Kind<F, User>;
readonly date: Kind<F, Date>;
readonly comment: Kind<F, string>;
readonly state: Kind<F, OrderState>;
}
type Order = OrderHKD<identity.URI>;
type OrderOption = OrderHKD<option.URI>;
const validateOrder = (inputOrder: OrderOption): option.Option<Order> =>
pipe(inputOrder, apply.sequenceS(option.Apply));
// ^
// | here
// Argument of type '<NER extends Record<string, Option<any>>>(r: EnforceNonEmptyRecord<NER>) => Option<{ [K in keyof NER]: [NER[K]] extends [Option<infer A>] ? A : never; }>' is not assignable to parameter of type '(a: OrderOption) => Option<{ [x: string]: any; }>'.
// Types of parameters 'r' and 'a' are incompatible.
// Type 'OrderOption' is not assignable to type 'Record<string, Option<any>>'.
// Index signature for type 'string' is missing in type 'OrderHKD<"Option">'.ts(2345)
CodePudding user response:
I don't know how this code could have worked, since the result of sequenceS
has a constraint <NER extends Record<string, Kind<F, any>>>
, which cannot be met by an interface due to possible declaration merging (see this TypeScript issue, for example). And that constraint was already present in 2019, which is way before the blog post was written.
Anyhow, you can get the example to work by declaring OrderHKD
as a type
rather than an interface
:
type OrderHKD<F extends URIS> = {
readonly id: Kind<F, OrderId>;
readonly issuer: Kind<F, User>;
readonly date: Kind<F, Date>;
readonly comment: Kind<F, string>;
readonly state: Kind<F, OrderState>;
}