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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods in simple mixin result as type any. #39943

Open
trusktr opened this issue Aug 7, 2020 · 3 comments
Open

Methods in simple mixin result as type any. #39943

trusktr opened this issue Aug 7, 2020 · 3 comments
Labels
Needs Investigation This issue needs a team member to investigate its status.
Milestone

Comments

@trusktr
Copy link
Contributor

trusktr commented Aug 7, 2020

TypeScript Version: 3.9.2

Search Terms:

typescript mixin method is any

Code

type AnyCtor = new (...a: any[]) => any

function Foo<T extends AnyCtor>(Base: T) {
	return class Foo extends Base {
		foo() {}
	}
}
function Bar<T extends AnyCtor>(Base: T) {
	return class Bar extends Base {
		bar() {}
	}
}
function One<T extends AnyCtor>(Base: T) {
	return class One extends Base {
		one() {}
	}
}
function Two<T extends AnyCtor>(Base: T) {
	return class Two extends Base {
		two() {}
	}
}
function Three<T extends AnyCtor>(Base: T) {
	return class Three extends One(Two(Base)) {
		three() {}
	}
}

class MyClass extends Three(Foo(Bar(Object))) {
	test() {
		// @ts-expect-error
		this.foo(123)
		// @ts-expect-error
		this.bar(123)
		// @ts-expect-error // ERROR
		this.one(123) // this.one is type `any`!
		// @ts-expect-error // ERROR
		this.two(123) // this.two is type `any`!
		// @ts-expect-error
		this.three(123)
		console.log('no runtime errors')
	}
}

const m = new MyClass()
m.test()

Expected behavior:

There should be an error on all the lines marked with // @ts-expect-error

Actual behavior:

There is no type error on the lines with this.one and this.two because this.one and this.two are seen as type any.

The expectation is that the one and two methods have the proper type (with zero parameters) which would therefore cause a type error from passing in arguments.

Playground Link

Related Issues:

Someone from the Discord chat thought perhaps #29571 might be related, but not with 100% certainty. They do however think this is a bug.

Ultimately, making mixins in TypeScript is too hard. It's too easy to get them wrong and they become a very inconvenient in TypeScript (whereas they are very convenient in plain JavaScript).

Also related: #32080

@trusktr
Copy link
Contributor Author

trusktr commented Aug 7, 2020

The following might be a hint at the bug: when we change type AnyCtor = new (...a: any[]) => any to type AnyCtor = new (...a: any[]) => object, then the example works as expected:

playground

It doesn't seem that a generic constraint should dictate what the type of a generic arg actually is. It seems a generic arg should only be constrained. Once a generic arg passes the constraint and is allowed to be passed in, then the type of the generic parameter should be based on what the passed-in arg's type actually is, not what it is constrained to.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Sep 2, 2020
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Sep 2, 2020
@jcalz
Copy link
Contributor

jcalz commented Nov 29, 2023

An SO question ran into this issue. Is it a TS bug?

@trusktr
Copy link
Contributor Author

trusktr commented Nov 29, 2023

I'd say this is a bug, because regardless if the constructor return constraint is any or object, it should be the actual T that informs the final type. That's my feeling from an end user perspective.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

3 participants