如何使用typescript给promise增加一个属性?
关注者
4被浏览
6,6143 个回答
诺,这是你想要的:
interface Promise<T> {
cancelWith (v: T): void
}
function sleep(timeout: number): Promise<'done' | undefined> {
let res!: (v: 'done' | undefined) => void
const promise = new Promise<'done' | undefined>(resolve => {
res = resolve
setTimeout(() => {
resolve('done')
}, timeout)
})
promise.cancelWith = res;
return promise
}
但是俺想不明白为啥要给 promise 增加属性,这岂不是会让其他人误用 Promise,虽然没有污染原型,但污染了类型呀?建议这样写:
interface CancelablePromise<T> extends Promise<T> {
cancelWith (v: T): void
}
function cancelableSleep(timeout: number): CancelablePromise<'done' | undefined> {
let res!: (v: 'done' | undefined) => void
const promise = new Promise<'done' | undefined>(resolve => {
res = resolve
setTimeout(() => {
resolve('done')
}, timeout)
})
return Object.assign(promise, { cancelWith: res })
}
其实俺也不建议这样写,俺就是顺着你思路来了这么一下子,俺自己大概会这样写吧:
function sleep(timeout: number) {
return new Promise(resolve => setTimeout(resolve, timeout))
}
function createControlable<T>() {
let resolve!: (v: Promise<T> | T) => void
let reject!: () => void
const promise = new Promise<T>((res, rej) => {
resolve = res
reject = rej
});
return Object.assign(promise, {
resolve,
reject,
})
}
interface ControlSignals<T> {
abort (): void
hang(): void
cancelWith(v: T): void
}
function withControlSignals<T>(p: Promise<T>): Promise<T> & ControlSignals<T> {
const controlable = createControlable<T>();
const racing = Promise.race([
p.then(v => (controlable.resolve(v), controlable)),
controlable
])
return Object.assign(racing, {
abort() {
controlable.reject()
},
hang() {
controlable.resolve(new Promise<T>(() => {}))
},
cancelWith(v: T) {
controlable.resolve(v)
},
})
}
const test1 = withControlSignals(sleep(5000).then(() => 'test1'))
// 5 秒后正常输出 test1
test1.then(console.log)
const test2 = withControlSignals(sleep(5000).then(() => 'test2'))
test2.then(console.log)
// 5 秒后 throw 一个 error,可以 async try await catch finally
test2.abort()
const test3 = withControlSignals(sleep(5000).then(() => 'test3'))
test3.then(console.log)
// 啥也不搞
test3.hang()
const test4 = withControlSignals(sleep(5000).then(() => 'test4'))
test4.then(console.log)
// 用自定义的输出
test4.cancelWith('BAZINGA')
写的有点复杂了(过度设计了嘛?),不过俺寻思你的需求是可以解构出一个原始的 sleep,一个控制流的,估摸这样子用接口表达出来以后更方便扩展吧?可组合可复用,专注点也分离掉了...
type CancelablePromise = Promise<any> & {cancel: any}
function sleep(timeout: number): CancelablePromise {
let res
let promise = new Promise(resolve => {
res = resolve
setTimeout(() => {
resolve('done')
}, timeout)
}) as CancelablePromise
promise.cancel = res;
return promise
}