未验证 提交 a77da1b1 编写于 作者: M Matt Bierner 提交者: GitHub

For #81574 (#84669)

Our code currently uses the `IConstructorSignature` types in a two main ways:

- As argument types in functions that take a service constructor.
- As return types or property types when we expose a service constructor in the API

This first usage is not valid with strict function types. The reason is that the `IConstructorSignature` types takes a rest array of `...services: BrandedService[]` , while the concrete constructors you pass in use actual services. With strict function types, you cannot convert the concrete constructor type to an `IConstructorSignature` because this would drop important type information that the implementation needs. As an example

```ts
class Foo {
    constructor(@ILogService service: ILogService) {}
}

registerFoo(Foo);

// The type of `ctor` inlines `IConstructorSignature0`
function registerFoo(ctor: { new(....serivces: BrandedService[]): Foo}) {
   // When registerFoo(Foo) is called, the implementation here would need to know that
   // ctor needs to be invoked with exactly one `ILogService`. However the type of `IConstructorSignature0`
   // does not express this. Strict function types therefore disallows this conversion
}
```

To fix this, I have converted a few places were we were taking `IConstructorSignature` arguments so that they preserve the full type of the constructor. This fixed over half of our 900 strict function type errors. Unfortunatly I can not figure out a more elegant way to express this besides inlining the types

However, even after this change, we still need to figure out how to deal with:

- Places in the code where `IConstructorSignature` is exposed as a return type or object property
- How to deal with all of our descriptor types (such as `SyncActionDescriptor`)
上级 92caa97a
......@@ -16,7 +16,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -303,7 +303,7 @@ export function registerInstantiatedEditorAction(editorAction: EditorAction): vo
EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);
}
export function registerEditorContribution(id: string, ctor: IEditorContributionCtor): void {
export function registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void {
EditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor);
}
......@@ -355,7 +355,7 @@ class EditorContributionRegistry {
this.editorCommands = Object.create(null);
}
public registerEditorContribution(id: string, ctor: IEditorContributionCtor): void {
public registerEditorContribution<Services extends BrandedService[]>(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }): void {
this.editorContributions.push({ id, ctor });
}
......
......@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { SyncDescriptor } from './descriptors';
import { ServiceIdentifier, IConstructorSignature0 } from './instantiation';
import { ServiceIdentifier, BrandedService } from './instantiation';
const _registry: [ServiceIdentifier<any>, SyncDescriptor<any>][] = [];
export function registerSingleton<T>(id: ServiceIdentifier<T>, ctor: IConstructorSignature0<T>, supportsDelayedInstantiation?: boolean): void {
export function registerSingleton<T, Services extends BrandedService[]>(id: ServiceIdentifier<T>, ctor: { new(...services: Services): T }, supportsDelayedInstantiation?: boolean): void {
_registry.push([id, new SyncDescriptor<T>(ctor, [], supportsDelayedInstantiation)]);
}
......
......@@ -22,7 +22,7 @@ export namespace _util {
// --- interfaces ------
type BrandedService = { _serviceBrand: undefined };
export type BrandedService = { _serviceBrand: undefined };
export interface IConstructorSignature0<T> {
new(...services: BrandedService[]): T;
......@@ -101,7 +101,8 @@ export interface IInstantiationService {
createInstance<A1, A2, A3, A4, A5, A6, A7, T>(descriptor: descriptors.SyncDescriptor7<A1, A2, A3, A4, A5, A6, A7, T>, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): T;
createInstance<A1, A2, A3, A4, A5, A6, A7, A8, T>(descriptor: descriptors.SyncDescriptor8<A1, A2, A3, A4, A5, A6, A7, A8, T>, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): T;
createInstance<Ctor extends new (...args: any) => any, R extends InstanceType<Ctor>>(t: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
createInstance<Ctor extends new (...args: any[]) => any, R extends InstanceType<Ctor>>(t: Ctor, ...args: GetLeadingNonServiceArgs<ConstructorParameters<Ctor>>): R;
createInstance<Services extends BrandedService[], Ctor extends new (...services: Services) => any, R extends InstanceType<Ctor>>(t: Ctor): R;
/**
*
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation';
import { IConstructorSignature1, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
......@@ -13,12 +13,12 @@ export type IExtHostNamedCustomer<T extends IDisposable> = [ProxyIdentifier<T>,
export type IExtHostCustomerCtor<T extends IDisposable> = IConstructorSignature1<IExtHostContext, T>;
export function extHostNamedCustomer<T extends IDisposable>(id: ProxyIdentifier<T>) {
return function (ctor: IExtHostCustomerCtor<T>): void {
return function <Services extends BrandedService[]>(ctor: { new(context: IExtHostContext, ...services: Services): T }): void {
ExtHostCustomersRegistryImpl.INSTANCE.registerNamedCustomer(id, ctor);
};
}
export function extHostCustomer<T extends IDisposable>(ctor: IExtHostCustomerCtor<T>): void {
export function extHostCustomer<T extends IDisposable, Services extends BrandedService[]>(ctor: { new(context: IExtHostContext, ...services: Services): T }): void {
ExtHostCustomersRegistryImpl.INSTANCE.registerCustomer(ctor);
}
......
......@@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IAction } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
/**
* The action bar contributor allows to add actions to an actionbar in a given context.
......@@ -134,7 +134,7 @@ export interface IActionBarRegistry {
* Registers an Actionbar contributor. It will be called to contribute actions to all the action bars
* that are used in the Workbench in the given scope.
*/
registerActionBarContributor(scope: string, ctor: IConstructorSignature0<ActionBarContributor>): void;
registerActionBarContributor<Services extends BrandedService[]>(scope: string, ctor: { new(...services: Services): ActionBarContributor }): void;
/**
* Returns an array of registered action bar contributors known to the workbench for the given scope.
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { runWhenIdle, IdleDeadline } from 'vs/base/common/async';
......@@ -19,7 +19,7 @@ export namespace Extensions {
export const Workbench = 'workbench.contributions.kind';
}
export type IWorkbenchContributionSignature = IConstructorSignature0<IWorkbenchContribution>;
type IWorkbenchContributionSignature<Service extends BrandedService[]> = new (...services: Service) => IWorkbenchContribution;
export interface IWorkbenchContributionsRegistry {
......@@ -29,7 +29,7 @@ export interface IWorkbenchContributionsRegistry {
*
* @param phase the lifecycle phase when to instantiate the contribution.
*/
registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void;
registerWorkbenchContribution<Services extends BrandedService[]>(contribution: IWorkbenchContributionSignature<Services>, phase: LifecyclePhase): void;
/**
* Starts the registry by providing the required services.
......@@ -43,8 +43,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry
private readonly toBeInstantiated: Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]> = new Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]>();
registerWorkbenchContribution(ctor: IWorkbenchContributionSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void {
registerWorkbenchContribution<Services extends BrandedService[]>(ctor: { new(...services: Services): IWorkbenchContribution }, phase: LifecyclePhase = LifecyclePhase.Starting): void {
// Instantiate directly if we are already matching the provided phase
if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) {
this.instantiationService.createInstance(ctor);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册