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
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.
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.
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 🕺.