不同 return 类型的 TypeScript 重载
TypeScript Overload with different return types
作为练习,我正在尝试将 Maybe
模式从类似 Haskell 的语言重新实现到 TypeScript 中。到目前为止一切顺利,我得到了一个令人满意的结果,而且它工作得很好,有一些我必须手动覆盖的类型检查内容。
我想更 JavaScript-ish 一点,我尝试定义一个函数映射,它可以 return 纯数据或数据承诺。
这里有一些代码更清楚:
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()
}
}
}
我想知道是否可以像上面定义的那样定义 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()
}
}
}
所以现在 Maybe.just(0).map(x=>x+1)
是 Maybe<number>
但 Maybe.just(0).map(x=>Promise.resolve(x+1))
是 Promise<Maybe<number>>
但是对于 Maybe.nothing().map(x=>Promise.resolve(x+1))
你会收到 Maybe<number>
而接口会声明 Promies<Maybe<number>>
所以这不是一个好主意,因为你无法告诉函数 return 类型在运行时不调用它
作为练习,我正在尝试将 Maybe
模式从类似 Haskell 的语言重新实现到 TypeScript 中。到目前为止一切顺利,我得到了一个令人满意的结果,而且它工作得很好,有一些我必须手动覆盖的类型检查内容。
我想更 JavaScript-ish 一点,我尝试定义一个函数映射,它可以 return 纯数据或数据承诺。
这里有一些代码更清楚:
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()
}
}
}
我想知道是否可以像上面定义的那样定义 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()
}
}
}
所以现在 Maybe.just(0).map(x=>x+1)
是 Maybe<number>
但 Maybe.just(0).map(x=>Promise.resolve(x+1))
是 Promise<Maybe<number>>
但是对于 Maybe.nothing().map(x=>Promise.resolve(x+1))
你会收到 Maybe<number>
而接口会声明 Promies<Maybe<number>>
所以这不是一个好主意,因为你无法告诉函数 return 类型在运行时不调用它