Overview
VS Code uses constructor-based dependency injection with decorators to declare service dependencies. The Instantiation Service creates instances with all their dependencies automatically resolved.Core Concepts
Service Identifiers
Services are identified by uniqueServiceIdentifier tokens created with createDecorator:
Service Brand: The
_serviceBrand property is a TypeScript trick that ensures type safety. It’s never actually used at runtime but prevents accidental type mismatches.Service Implementation
Implement services as classes and declare dependencies using parameter decorators:Registering Services
Register services usingServiceCollection or SyncDescriptor:
The IInstantiationService Interface
Common Usage Patterns
Creating Instances with Dependencies
Creating Instances with Dependencies
Use You can also pass additional static arguments:
createInstance() to instantiate classes with automatic dependency resolution:Using invokeFunction for Service Access
Using invokeFunction for Service Access
invokeFunction() lets you access services without creating a class:Creating Child Instantiation Services
Creating Child Instantiation Services
Child services inherit parent services but can override specific ones:This is commonly used for:
- Testing (mocking services)
- Scoped services (window-specific, editor-specific)
- Isolated contexts
Service Descriptors
SyncDescriptor enables lazy service instantiation:
- Services are only created when first accessed
- Reduces startup time
- Enables cyclic dependency resolution
- Supports delayed instantiation via proxies
Advanced Features
Cyclic Dependency Detection
The Instantiation Service detects and reports cyclic dependencies:Delayed Instantiation
Services can opt into delayed instantiation using proxies:- A proxy is returned immediately
- The real service is created during idle time or on first property access
- Event subscriptions work correctly before instantiation
- Improves startup performance for heavy services
Service Collection
Real-World Example
Here’s how the Editor service is typically structured:Best Practices
Always use interfaces: Define service interfaces separately from implementations. This enables testing with mock implementations.
One service identifier per service: Each service should have exactly one
ServiceIdentifier. Don’t create multiple identifiers for the same service.Minimize constructor logic: Keep constructor logic minimal. Use initialization methods or lifecycle hooks for complex setup.
Dispose resources: If your service holds resources (subscriptions, file handles), implement
IDisposable and clean up in dispose().