¿Cómo hacer que los tipos fantasma funcionen con métodos en TypeScript?
Considere el siguiente programa que utiliza tipos fantasma:
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); // funciona
contramap(strlen, constant); // funciona
El programa anterior se verifica correctamente porque se infieren los tipos correctos. El valor constant
tiene el tipo inferido Const<boolean, never="">
. La función map
se llama con los tipos A = boolean
, B = string
y C = number
. La función contramap
se llama con los tipos A = boolean
, B = number
y C = string
.
Sin embargo, sería bueno escribir las expresiones anteriores utilizando métodos en lugar de funciones. Por lo tanto, intenté lo siguiente:
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); // funciona
constant.contramap(strlen); // error
Como se puede ver, el método map
funciona pero el método contramap
no. Esto se debe a que el tipo de constant
es Const<boolean, never="">
y no se refina con la llamada al método, es decir, para map
el tipo no se refina a Const<boolean, string="">
y para contramap
el tipo no se refina a Const<boolean, number="">
.
Debido a esto, tanto map
como contramap
funcionan pero no ambos. Si el tipo del objeto es Const<boolean, never="">
, entonces contramap
no funciona. Si el tipo del objeto es Const<boolean, unknown="">
, entonces map
no funciona.
¿Cómo puedo hacer que tanto map
como contramap
funcionen utilizando métodos en lugar de funciones?</boolean,></boolean,></boolean,></boolean,></boolean,></a,></a,></a,></a,></a,></boolean,></a,></a,></a,></a,></a,></a,></a,></a,></a,>
davy.ai
Para hacer que tanto
map
comocontramap
funcionen utilizando métodos en lugar de funciones, podemos utilizar el encadenamiento de métodos y devolverthis
con el tipo refinado después de cada llamada al método. Aquí está una versión actualizada del código:En esta versión, llamar a
map
ocontramap
devuelveConst<a, c="">
en lugar de soloConst<a, b="">
. Luego podemos encadenar varias llamadas de método juntas para refinar aún más el tipo.Tenga en cuenta que también necesitamos especificar el tipo del argumento en la llamada de
contramap
para ayudar a TypeScript a inferir el tipo correcto.</a,></a,></a,></a,></a,></a,></a,>