-
Notifications
You must be signed in to change notification settings - Fork 13k
Closed as not planned
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed
Description
🔎 Search Terms
"intra expression inference class", "context sensitive class inference"
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about context sensitive inference
⏯ Playground Link
💻 Code
class Foo<T> {
constructor(public inner: T) {}
}
class BarClass<T> {
constructor(public accessor: (state: T) => boolean) {}
}
{
// This is my actual production use case, narrowed down.
// `bars` is an array of class instances with a generic inferred from
// context of previous function calls.
class Container<C, F> {
constructor(
public ctx: C,
public fooFactory: (ctx: C) => F,
public bars: BarClass<F>[],
) {}
}
const container = new Container(
42,
ctx => new Foo({ answer: ctx }),
[new BarClass(state => true)],
// ^?
// state is unknown
)
}
{
// The problem exists with a singular instance of the class however.
class Container<C, F> {
constructor(
public ctx: C,
public fooFactory: (ctx: C) => F,
public bar: BarClass<F>,
) {}
}
const containerWithoutAnnotation = new Container(
42,
ctx => new Foo({ answer: ctx }),
new BarClass(state => true),
// ^?
// state is unknown
)
const containerWithAnnotation = new Container(
42,
(ctx: number) => new Foo({ answer: ctx }), // an explicit type annotation on ctx here fixes the issue
new BarClass(state => true), // in all cases, but isn't practical for my API use case
// ^?
// state is Foo<{ answer: number }>
)
}
{
// Having a factory function with no arguments doesn't help
class Container<C, F> {
constructor(
public ctx: C,
public fooFactory: (ctx: C) => F,
public barFactory: () => BarClass<F>,
) {}
}
const container = new Container(
42,
ctx => new Foo({ answer: ctx }),
() => new BarClass(state => true),
// ^?
// state is unknown
)
}
{
// A factory function with a dummy argument _does_ work
class Container<C, F> {
constructor(
public ctx: C,
public fooFactory: (ctx: C) => F,
public barFactory: (dummy: never) => BarClass<F>,
) {}
}
const containerWithDummy = new Container(
42,
ctx => new Foo({ answer: ctx }),
dummy => new BarClass(state => true),
// ^?
// state is Foo<{ answer: number }>
)
// however if the dummy argument isn't passed, it doesn't work
const containerWithWrongArity = new Container(
42,
ctx => new Foo({ answer: ctx }),
() => new BarClass(state => true),
// ^?
// state is unknown
)
}
{
type BarObject<T> = {
accessor: (state: T) => boolean
}
// A regular object is inferred correctly.
class Container<C, F> {
constructor(
public ctx: C,
public fooFactory: (ctx: C) => F,
public bar: BarObject<F>,
) {}
}
const container = new Container(
42,
ctx => new Foo({ answer: ctx }),
{ accessor: state => true },
// ^?
// state is Foo<{ answer: number }>
)
}
🙁 Actual behavior
The BarClass type isn't inferred correctly.
🙂 Expected behavior
I think I'd expect BarClass to be inferred in all those cases? Except perhaps when the dummy argument is in the function signature, but the passed function has the wrong arity.
Additional information about the issue
Under the umbrella of #47599
This PR+comment feels close #54183 (review)
Metadata
Metadata
Assignees
Labels
Design LimitationConstraints of the existing architecture prevent this from being fixedConstraints of the existing architecture prevent this from being fixed