Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decorators on arrow functions produce unexpected results #50378

Open
ingvardm opened this issue Aug 19, 2022 · 4 comments
Open

Decorators on arrow functions produce unexpected results #50378

ingvardm opened this issue Aug 19, 2022 · 4 comments
Labels
Needs More Info The issue still hasn't been fully clarified

Comments

@ingvardm
Copy link

ingvardm commented Aug 19, 2022

Bug Report

馃攷 Search Terms

decorator arrow functions async generator

馃捇 Code

this works as expected

export default class Que {
	private static async * makeStream(): AsyncGenerator<unknown, any, any> {
		let r = yield
		while (1) r = yield await r()
	}

	q = Que.makeStream()

	constructor() {
		this.q.next()
	}

	add = async <T>(fn: (...args: any[]) => Promise<T>) => (await this.q.next(fn)).value as T
}

export function qued(
	_: unknown,
	__: string,
	descriptor: PropertyDescriptor,
) {
	const que = new Que()
	const original = descriptor.value

	descriptor.value = async function (...args: any[]) {
		return que.add(() => original.call(this, ...args)) as Promise<ReturnType<typeof original>>
	}
}

class Tested {
	count: number[] = []

	@qued
	async testMethod(v: number) {
		return new Promise<number>(resolve => {
			setTimeout(() => {
				this.count.push(v)
				resolve(v)
			}, 20 - v * 2)
		})
	}
}

async function test(){
	const testedInstance = new Tested()

	for (const val of [1,2,3,4,5]) {
		testedInstance.testMethod(val)
	}

	await testedInstance.testMethod(6)

	console.log(testedInstance.count)
}

test()
 // [1,2,3,4,5,6]

this doesn't

export default class Que {
	private static async * makeStream(): AsyncGenerator<unknown, any, any> {
		let r = yield
		while (1) r = yield await r()
	}

	q = Que.makeStream()

	constructor() {
		this.q.next()
	}

	add = async <T>(fn: (...args: any[]) => Promise<T>) => (await this.q.next(fn)).value as T
}

export function qued(
	_: unknown,
	__: string,
	descriptor?: PropertyDescriptor, // <--
) {
	const que = new Que()
	const original = descriptor!.value

	descriptor!.value = async function (...args: any[]) {
		return que.add(() => original.call(this, ...args)) as Promise<ReturnType<typeof original>>
	}
}

class Tested {
	count: number[] = []

	@qued
	testMethod = async (v: number) => { // <-- turn into arrow function
		return new Promise<number>(resolve => {
			setTimeout(() => {
				this.count.push(v)
				resolve(v)
			}, 20 - v * 2)
		})
	}
}

async function test(){
	const testedInstance = new Tested()

	for (const val of [1,2,3,4,5]) {
		testedInstance.testMethod(val)
	}

	await testedInstance.testMethod(6)

	console.log(testedInstance.count)
}

test()
 // [6]

when the method is static or not an arrow function - everything works as expected
however, when the method is written as arrow function this happens
am i missing something?

Que.add() works as expected if used without the decorator

@MartinJohns
Copy link
Contributor

Perhaps you can provide a playground link, as the issue template asked for? The code you provided does not work.

@ingvardm
Copy link
Author

ingvardm commented Aug 20, 2022

Perhaps you can provide a playground link, as the issue template asked for? The code you provided does not work.

the typescript playground has too many issues with running typescript so i cant.
I've edited the original post to include 2 examples that i can compile and run, sorry if the first one was broken!

EDIT: it looks like, when you use arrow function its not initialized in the decorator but after the decorator returns the property is initialized and overridden with the original function. In any case we need a way to decorate arrow functions as well as normal properties.

@fatcerberus
Copy link

the typescript playground has too many issues with running typescript so i cant.

Such as?

@DanielRosenwasser
Copy link
Member

I tried it out - you get lib errors if you're not using a newer target and on top of that, the playground uses JSX which interferes with generic arrow function syntax. Kind of a pain, but you can get it get rid of the errors by setting JSX to none and using /// <reference lib="esnext" />.

Still, can you at least provide something like the tsconfig options?

@DanielRosenwasser DanielRosenwasser added the Needs More Info The issue still hasn't been fully clarified label Aug 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

4 participants