Skip to content

Contextually type this inside function* from a leading thisArg #63755

Description

@bun-unsafe

🔍 Search Terms

function* this implicit any
generator thisArg contextual this
noImplicitThis function*
Effect.gen this function*
this parameter generator callback
site:github.com/microsoft/TypeScript generator thisArg
related: #12548 (thisArg for Array#forEach callbacks)

✅ Viability Checklist

⭐ Suggestion

Type this inside a function* expression from a leading thisArg (or from an explicit this parameter on the callback type), the same way Array#forEach already contextually types this from its thisArg.

Today a nested function* used as a callback gets this: any under noImplicitThis / strict, even when:

  1. it is created inside a class method, and
  2. the callee’s first argument is a thisArg whose type is the enclosing instance.

No new syntax. No emit change. Existing code that already writes function* (this: Foo) or fn(this, function* () { ... }) should just type-check.

This is the type-checker analogue of #12548, but for generator function expressions rather than Array callbacks.

📃 Motivating Example

You can write Effect-style / yield* programs inside a class method and this is just the instance — no function* (this: this) annotation, and no extra thisArg ceremony for the type checker.

class Form {
  model = { name: "" }

  run(gen: (this: this) => Generator<unknown, string>) {
    return gen.call(this)
  }

  submit() {
    return this.run(function* () {
      return this.model.name // today: TS2683, `this` is implicit any
    })
  }
}


If this shipped, the this inside that function* would be Form, because the callback type already says (this: this) => ....
  1. What do you want to use this for?

Class-based controllers that build a generator program and yield* methods on this (Vue + Effect-style Effect.gen(this, function* () { ... })). This pattern appears in 50+ files in one app. The runtime already passes the instance as thisArg; only the types are missing.

  1. What shortcomings exist with current approaches?
  • A nested function* does not get contextual this from a this parameter on the callback type.
  • Arrow functions have lexical this but cannot yield* (and new generator syntax would be a JS proposal, which this issue is not requesting).
  • async/await only unwraps Promise and cannot carry a typed error channel, so generators are the do-notation that exists today.
  1. What workarounds are you using in the meantime?
// Workaround A — repeat the class type on every generator
Effect.gen(this, function* (this: FormController) {
  yield* this.submitModel(decoded)
})

// Workaround B — pass thisArg at runtime and still annotate `this`
Effect.gen(this, function* () {
  yield* this.submitModel(decoded) // still TS2683 without an annotation
})

Both are noise. The runtime thisArg is already correct.

Observed on TypeScript 6.0.3 and 7.0.2 (same language surface; not a native-port regression).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions