fp-ts 如何让 'HKT<F, T>' 类型统一为 'F<T>'

How does fp-ts get the `HKT<F, T>` type to unify to `F<T>`

提问人:A Question Asker 提问时间:9/22/2023 更新时间:9/26/2023 访问量:70

问:

我已经阅读了HKT https://github.com/gcanti/fp-ts/blob/master/docs/guides/HKT.md 的解释,并开始阅读代码...我了解嵌入并能够使用它,但我不太确定它是如何工作的,即打字稿编译器。在我看来很神奇的部分是,当您使用 end 方法时,类型将是 ,而不是......我很好奇那座桥是怎么发生的F<T>HKT<F,T>

打字稿 typescript-generics fp-ts

评论


答:

2赞 Souperman 9/26/2023 #1

剥离相关代码和 HKT 解决方法,只看 TypeScript,请考虑以下代码:fp-ts

type Shape<T> = T extends Array<any> ? 'array' : 'value';

interface IFoo<T> {
    value: Shape<T>;
}

type test1 = IFoo<number>['value'];
//    ^? "value"
type test2 = IFoo<number[]>['value'];
//    ^? "array"

操场

当 TypeScript 计算出接口中索引字段的类型时,它会尝试尽可能简化值。在此示例中,您可以看到它计算条件类型并返回文本类型值。Shape

回到 HKT 的方法,我们也有类似的东西。有一个接口,用于从开发人员选择的字符串指向泛型类型。TypeScript 不允许你传递泛型类型,但它会让你传递字符串文字,并允许你索引到带有这些文字的接口中。它还将尝试尽可能简化类型。fp-tsURItoKindShape

对于像 这样的内容,URI 被选为键,类型被隐藏起来,以便可以在更高种类的函数中查找它,并且当您有一个具体的实例时,类型检查器能够再次解析,拉走层。Functor<T>'Functor'URIToKindFunctor<T>

这是我自己对标识示例的注释,以说明正在发生的事情。

// Functor1 is going to pull values out of URIToKind
import { Functor1 } from 'fp-ts/Functor'

// Pick a name for the Identity type in the map.
export const URI = 'Identity'

// Make that chosen name available outside the module
export type URI = typeof URI

declare module 'fp-ts/HKT' {
  // Set up a mapping from the literal string we chose to the actual
  // * -> * Identity generic type
  interface URItoKind<A> {
    readonly Identity: Identity<A>
  }
}

// Make Identity available outside the module (and actually define behavior)
export type Identity<A> = A

// Functor instance
// Functor1<URI> is doing a lot of work here. URI is the 'Identity' literal
// we chose, and `Functor1` is looking into the `URIToKind` map, indexing
// it with 'Identity' to get out the `Identity<A>` type which TS will then
// see it cannot refine further because it doesn't know `A` yet. It ends
// up with <A>(ma: Identity<A>, (a: A) => A) => A
export const Functor: Functor1<URI> = {
  URI,
  map: (ma, f) => f(ma)
}