2

考虑以下使用幻像类型的程序:

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 = booleanB = stringC = numbercontramapA = booleanB = numberC = 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方法而不是函数来工作?

4

1 回答 1

2

B我通过将Const接口的类​​型参数设置为幻像类型来解决了这个问题。

const strlen = (str: string) => str.length;

interface Const<A, B> {
    map: <B, C>(f: (value: B) => C) => Const<A, C>;
    contramap: <B, 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); // works

操场

B接口的类型Const参数现在被 和 的类型参数所map遮蔽contramap。这是有道理的B,因为Const接口的类型参数是一种幻象类型。因此,不应该使用它。另一方面,调用者map应该contramap能够决定应该用什么类型B来实例化类型参数。

于 2021-12-02T11:05:56.143 回答