Skip to content
Notifications
Clear all

How do I make Copilot suggest more functional patterns in JavaScript instead of classes?

4 Posts
4 Users
0 Reactions
2 Views
(@code_weaver_max)
Estimable Member
Joined: 2 months ago
Posts: 129
Topic starter   [#10058]

Hey folks! I've been using Copilot for JavaScript/TypeScript a ton lately, and I've noticed a pattern: it *really* loves suggesting ES6 classes. While that's fine for some projects, I'm working in a codebase that favors functional composition and pure functions. Getting Copilot to suggest `pipe`, `compose`, or even just simple factory functions can feel like pulling teeth sometimes.

I've had some success by explicitly priming it. For example, if I start typing a JSDoc comment or a signature, it catches on:

```javascript
// Using fp-ts and pipe
import { pipe } from 'fp-ts/lib/function'

// I start typing this...
const transformUserData = (users) => pipe(

// Copilot will often now suggest:
users,
map(addFullName),
filter(isActive),
sort(byRegistrationDate)
)
```

But without that leading context, it often jumps straight to `class UserTransformer`.

Has anyone else wrestled with this? What tricks or patterns in your prompts/comments have steered Copilot toward more functional suggestions?

A few things I've tried:
- Adding `// functional style` or `// no classes` at the top of the file.
- Defining small utility functions (`map`, `filter`) myself early in the file, even if I'm using a library later.
- Using a `.copilot` instructions file (still experimenting with this).

Would love to hear your workflows! Especially if you're using Ramda, fp-ts, or similar patterns.

-- Weave


Prompt engineering is the new debugging


   
Quote
(@ericd)
Reputable Member
Joined: 1 week ago
Posts: 180
 

You've already hit on the key tactic, priming it with explicit context. That leading comment or import is basically Copilot's steering wheel.

I've found that dropping a few specific library names or even a signature pattern right at the top works wonders. Something like "// Using Ramda style" or starting the file with a small, generic `const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x)` can set a tone for the whole session. It seems to scan the immediate context for stylistic cues more than reading a general "no classes" instruction.

It can be frustrating, though. Sometimes it feels like you have to teach it your style file-by-file.


Keep it civil, keep it real.


   
ReplyQuote
(@integrations_ivan)
Estimable Member
Joined: 4 months ago
Posts: 125
 

You've identified the priming technique, which is fundamentally about establishing a context window with a strong functional signal. I've found that priming needs to be structural, not just a comment. The model's training data is saturated with OOP patterns, so you need to overwhelm that signal.

One effective method is to write a small, functional module signature at the top of your file before any implementation. This acts as a style guide for the entire generation session. For instance:

```javascript
// @ts-check
// Module: data-transforms
// Style: point-free, immutable, use pipe
import { pipe, flow } from 'fp-ts/function'
import * as A from 'fp-ts/Array'
import * as O from 'fp-ts/Option'

// Type definitions here establish vocabulary
// export type Transform = (a: Array) => Array
```

This gives Copilot a dense cluster of functional keywords, types, and imports to latch onto. The type definition, even commented out, introduces a functional "transform" concept. Now, when you start typing `const process = pipe(`, the surrounding context explicitly rejects class-based vocabulary.

The trick is that the priming block must be more information-dense than the latent class-oriented patterns in the model. A single "// functional style" comment gets drowned out. You need imports, type hints, and a concrete functional utility in the immediate context to bias the probability weights.


Single source of truth is a myth.


   
ReplyQuote
(@crm_hopper_2025)
Estimable Member
Joined: 2 months ago
Posts: 113
 

Oh, that trick of defining a generic compose function right at the top is a good one! I've done something similar by pasting in a few of my own common utility functions as a "style seed" at the file start. It's like giving Copilot a cheat sheet for the vocabulary I want it to use.

The "file-by-file" feeling is real, though. I've found it helps a little to maintain a tiny "priming" snippet in my notes app, just a block of imports and a few function signatures I can drop in. Saves the mental load of retyping that context every single time. Still, it's a bit of a dance 🕺.



   
ReplyQuote