考虑以下使用幻像类型的程序:
const strlen = (str: string) => str.length;
type Const<A, B> = { type: 'Const', value: A };
const Const = <A, B = never>(value: A): Const<A, B> => ({ type: 'Const', value });
const map = <A, B, C>(_f: (value: B) => C, { value }: Const<A, B>): Const<A, C> => Const(value);
const contramap = <A, B, C>(_f: (value: C) => B, { value }: Const<A, B>): Const<A, C> => Const(value);
const constant = Const(true);
map(strlen, constant); // works
contramap(strlen, constant); // works
上述程序类型检查是因为推断出正确的类型。该constant
值具有推断类型Const<boolean, never>
。该函数以、和map
类型调用。该函数以、和类型调用。A = boolean
B = string
C = number
contramap
A = boolean
B = number
C = string
但是,使用方法而不是函数来编写上述表达式会很好。因此,我尝试了以下方法:
const strlen = (str: string) => str.length;
interface Const<A, B> {
map: <C>(f: (value: B) => C) => Const<A, C>;
contramap: <C>(f: (value: C) => B) => Const<A, C>;
}
const Const = <A, B = never>(value: A): Const<A, B> => ({
map: () => Const(value),
contramap: () => Const(value)
});
const constant = Const(true);
constant.map(strlen); // works
constant.contramap(strlen); // error
如您所见,该map
方法有效,但该contramap
方法无效。这是因为 is 的类型constant
并且Const<boolean, never>
它没有被方法调用细化,即 formap
类型没有被细化到Const<boolean, string>
并且contramap
类型没有被细化到Const<boolean, number>
。
正因为如此,要么工作map
要么contramap
工作,但不能同时工作。如果对象的类型是Const<boolean, never>
则contramap
不起作用。如果对象的类型是Const<boolean, unknown>
则map
不起作用。
我怎样才能同时map
使用contramap
方法而不是函数来工作?