具有不同返回类型的TypeScript重载
作为练习,我试图将类似Haskell语言的具有不同返回类型的TypeScript重载,typescript,monads,Typescript,Monads,作为练习,我试图将类似Haskell语言的模式重新实现为TypeScript。到目前为止,我得到了一个令人满意的结果,它工作得很好,有一些类型检查的东西,我必须手动覆盖。 我想更像一点JavaScript语言,我尝试定义一个函数映射,它可以返回纯数据或承诺数据 这里有一些代码需要更清楚地说明: class Maybe<A> { #value: A | null private constructor(value: A) { this.#value = value
模式重新实现为TypeScript。到目前为止,我得到了一个令人满意的结果,它工作得很好,有一些类型检查的东西,我必须手动覆盖。
我想更像一点JavaScript语言,我尝试定义一个函数映射,它可以返回纯数据或承诺数据
这里有一些代码需要更清楚地说明:
class Maybe<A> {
#value: A | null
private constructor(value: A) {
this.#value = value
}
static just<A>(value: A): Maybe<A> {
return new Maybe(value)
}
static nothing<A>(): Maybe<A> {
return <Maybe<A>>(<unknown>new Maybe(null))
}
static nullable<A>(value: A | null): Maybe<A> {
if (value) {
return this.just(value)
} else {
return this.nothing()
}
}
value(): A {
if (this.#value) {
return this.#value
} else {
throw new Error('Maybe has no data')
}
}
map<B>(mapper: (a: A) => Promise<B>): Promise<Maybe<B>> // I got an error here in the overloading
map<B>(mapper: (a: A) => B): Maybe<B> {
if (this.#value) {
const result = mapper(this.#value)
if (result instanceof Promise) {
return result.then((e: B) => Maybe.just(e))
} else {
return new Maybe(mapper(this.#value))
}
} else {
return Maybe.nothing()
}
}
}
类{
#值:A | null
私有构造函数(值:A){
这个。#值=值
}
静态公正(值:A):也许{
返回新值(值)
}
静态无:可能{
返回(新的(空))
}
静态nullable(值:A | null):可能{
如果(值){
返回此值。just(值)
}否则{
还这个。没什么()
}
}
value():A{
如果(此值){
返回此值
}否则{
抛出新错误('可能没有数据')
}
}
map(mapper:(a:a)=>Promise):Promise//我在重载中遇到了一个错误
地图(制图员:(a:a)=>B):也许吧{
如果(此值){
常量结果=映射器(此值)
如果(承诺的结果实例){
返回结果。然后((e:B)=>Maybe.just(e))
}否则{
返回新值(映射器(此.#值))
}
}否则{
可能会回来
}
}
}
我想知道是否可以像上面定义的那样定义map函数?我想你可以这样做,看看注释
class Maybe<A> {
#value: A | null
// altered argument here
private constructor(value: A | null) {
this.#value = value
}
static just<A>(value: A): Maybe<A> {
return new Maybe(value)
}
static nothing<A>(): Maybe<A> {
// omitted casts
return new Maybe<A>(null);
}
static nullable<A>(value: A | null): Maybe<A> {
if (value) {
return this.just(value)
} else {
return this.nothing()
}
}
value(): A {
if (this.#value) {
return this.#value
} else {
throw new Error('Maybe has no data')
}
}
// added two separate declarations
map<B>(mapper: (a: A) => Promise<B>): Promise<Maybe<B>>;
map<B>(mapper: (a: A) => B): Maybe<B>;
// and single implementation which fits both declarations
map<B>(mapper: (a: A) => B | Promise<B>): Maybe<B> | Promise<Maybe<B>> {
if (this.#value) {
const result = mapper(this.#value)
if (result instanceof Promise) {
return result.then((e: B) => Maybe.just(e))
} else {
return new Maybe(result)
}
} else {
return Maybe.nothing()
}
}
}
类{
#值:A | null
//这里改变了论点
私有构造函数(值:A | null){
这个。#值=值
}
静态公正(值:A):也许{
返回新值(值)
}
静态无:可能{
//漏铸
返回newmaybe(null);
}
静态nullable(值:A | null):可能{
如果(值){
返回此值。just(值)
}否则{
还这个。没什么()
}
}
value():A{
如果(此值){
返回此值
}否则{
抛出新错误('可能没有数据')
}
}
//添加了两个单独的声明
地图(地图绘制者:(a:a)=>承诺):承诺;
地图(制图员:(a:a)=>B):可能;
//以及适合两种声明的单个实现
地图(地图绘制者:(a:a)=>B |承诺):也许|承诺{
如果(此值){
常量结果=映射器(此值)
如果(承诺的结果实例){
返回结果。然后((e:B)=>Maybe.just(e))
}否则{
返回新数据(结果)
}
}否则{
可能会回来
}
}
}
所以现在Maybe.just(0).map(x=>x+1)
isMaybe
但是Maybe.just(0).map(x=>Promise.resolve(x+1))
isPromise
然而对于Maybe.nothing().map(x=>Promise.resolve(x+1))
您将收到Maybe
,而接口将声明Promies
,所以这不是一个好主意,因为您无法在运行时告诉函数返回类型而不调用它什么错误?另外,考虑到B可能已经是承诺,为什么需要重载?此重载签名与其实现签名不兼容。
因为当您处理异步和可能时,我发现最好提供一个承诺
,而不是可能
(这在代码中非常类似),但是第一个允许你使用wait和continue Maybe链,而不必处理Maybe.map
中的承诺。嗯……是的,我明白你的意思。在我的第一个实现中,我得到了两个函数,一个是map
,另一个是asyncMap
,因此在第二种情况下,我总是有一个承诺。但是在这里,即使参数的类型不同,我们也不能在编译时决定调用两个不同的函数,对吗?不幸的是,我们不能。Typescript不提供上下文/类型感知转换