为何TypeScript无法正确推断Option ADT映射函数的类型?
修复Option类型的Functor map函数类型推断错误
以下是仿fp-ts实现的Option代数数据类型(ADT):
export type Option<A> = Some<A> | None export interface Some<A> { _tag: 'Some' value: A } export interface None { _tag: 'None' } export const some = <A>(x: A): Option<A> => ({ _tag: 'Some', value: x }) export const none: Option<never> = { _tag: 'None' } export const isNone = <A>(x: Option<A>): x is None => x._tag === 'None' type Match = <A, B>(onNone: () => B, onSome: (a: A) => B) => (x: Option<A>) => B const match: Match = (onNone, onSome) => x => isNone(x) ? onNone() : onSome(x.value)
尝试编写Option的Functor映射函数mapOption时,TypeScript无法正确推断类型,错误的mapOption代码如下:
type MapOption = <A, B>(f: (x: A) => B) => (fa: Option<A>) => Option<B> const mapOption: MapOption = f => fa => match( () => none, (value) => f(value))(fa)
问题原因
match的onSome分支直接返回f(value),但f(value)的类型是B,而我们需要返回的是Option<B>,类型不匹配;none的类型是Option<never>,TypeScript无法自动将其与Option<B>做统一类型推导。
修复方案
核心是让match的两个分支都返回Option<B>类型:
- 将
onSome分支的f(value)用some包裹,生成Some<B>类型的实例; - 确保
none能被TypeScript识别为Option<B>的子类型(Option<never>本身是所有Option<B>的子类型,只要另一个分支类型匹配即可自动推导)。
修复后的mapOption代码:
type MapOption = <A, B>(f: (x: A) => B) => (fa: Option<A>) => Option<B> const mapOption: MapOption = f => fa => match( () => none, (value) => some(f(value)) )(fa)
也可以省略MapOption类型定义,让TypeScript自动推导完整类型:
const mapOption = <A, B>(f: (x: A) => B) => (fa: Option<A>): Option<B> => match( () => none, (value) => some(f(value)) )(fa)
修改后TypeScript就能正确推断出返回类型为Option<B>,解决类型错误问题。
内容的提问来源于stack exchange,提问作者Shnd
相关产品推荐
相关产品推荐

