Skip to content

Commit 597e760

Browse files
authored
Merge pull request #5527 from NomicFoundation/improve-task-types
Improve the types of task arguments
2 parents 02fac13 + 8bf8959 commit 597e760

File tree

5 files changed

+184
-111
lines changed

5 files changed

+184
-111
lines changed

v-next/core/src/internal/tasks/builders.ts

+89-38
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import type {
1212
TaskOverrideDefinition,
1313
EmptyTaskDefinitionBuilder,
1414
EmptyTaskDefinition,
15+
ExtendTaskArguments,
16+
TaskArguments,
1517
} from "../../types/tasks.js";
1618

1719
import { HardhatError } from "@ignored/hardhat-vnext-errors";
@@ -55,8 +57,9 @@ export class EmptyTaskDefinitionBuilderImplementation
5557
}
5658
}
5759

58-
export class NewTaskDefinitionBuilderImplementation
59-
implements NewTaskDefinitionBuilder
60+
export class NewTaskDefinitionBuilderImplementation<
61+
TaskArgumentsT extends TaskArguments = TaskArguments,
62+
> implements NewTaskDefinitionBuilder<TaskArgumentsT>
6063
{
6164
readonly #id: string[];
6265
readonly #usedNames: Set<string> = new Set();
@@ -66,7 +69,7 @@ export class NewTaskDefinitionBuilderImplementation
6669

6770
#description: string;
6871

69-
#action?: NewTaskActionFunction | string;
72+
#action?: NewTaskActionFunction<TaskArgumentsT> | string;
7073

7174
constructor(id: string | string[], description: string = "") {
7275
validateId(id);
@@ -80,25 +83,32 @@ export class NewTaskDefinitionBuilderImplementation
8083
return this;
8184
}
8285

83-
public setAction(action: NewTaskActionFunction | string): this {
86+
public setAction(
87+
action: NewTaskActionFunction<TaskArgumentsT> | string,
88+
): this {
8489
validateAction(action);
8590

8691
this.#action = action;
8792

8893
return this;
8994
}
9095

91-
public addOption<T extends ArgumentType>({
96+
public addOption<
97+
NameT extends string,
98+
TypeT extends ArgumentType = ArgumentType.STRING,
99+
>({
92100
name,
93101
description = "",
94102
type,
95103
defaultValue,
96104
}: {
97-
name: string;
105+
name: NameT;
98106
description?: string;
99-
type?: T;
100-
defaultValue: ArgumentTypeToValueType<T>;
101-
}): this {
107+
type?: TypeT;
108+
defaultValue: ArgumentTypeToValueType<TypeT>;
109+
}): NewTaskDefinitionBuilder<
110+
ExtendTaskArguments<NameT, TypeT, TaskArgumentsT>
111+
> {
102112
const argumentType = type ?? ArgumentType.STRING;
103113

104114
const optionDefinition = {
@@ -115,32 +125,47 @@ export class NewTaskDefinitionBuilderImplementation
115125
return this;
116126
}
117127

118-
public addFlag(flagConfig: { name: string; description?: string }): this {
128+
public addFlag<NameT extends string>(flagConfig: {
129+
name: NameT;
130+
description?: string;
131+
}): NewTaskDefinitionBuilder<
132+
ExtendTaskArguments<NameT, ArgumentType.BOOLEAN, TaskArgumentsT>
133+
> {
119134
return this.addOption({
120135
...flagConfig,
121136
type: ArgumentType.BOOLEAN,
122137
defaultValue: false,
123138
});
124139
}
125140

126-
public addPositionalArgument<T extends ArgumentType>(argConfig: {
127-
name: string;
141+
public addPositionalArgument<
142+
NameT extends string,
143+
TypeT extends ArgumentType = ArgumentType.STRING,
144+
>(argConfig: {
145+
name: NameT;
128146
description?: string;
129-
type?: T;
130-
defaultValue?: ArgumentTypeToValueType<T>;
131-
}): this {
147+
type?: TypeT;
148+
defaultValue?: ArgumentTypeToValueType<TypeT>;
149+
}): NewTaskDefinitionBuilder<
150+
ExtendTaskArguments<NameT, TypeT, TaskArgumentsT>
151+
> {
132152
return this.#addPositionalArgument({
133153
...argConfig,
134154
isVariadic: false,
135155
});
136156
}
137157

138-
public addVariadicArgument<T extends ArgumentType>(argConfig: {
139-
name: string;
158+
public addVariadicArgument<
159+
NameT extends string,
160+
TypeT extends ArgumentType = ArgumentType.STRING,
161+
>(argConfig: {
162+
name: NameT;
140163
description?: string;
141-
type?: T;
142-
defaultValue?: Array<ArgumentTypeToValueType<T>>;
143-
}): this {
164+
type?: TypeT;
165+
defaultValue?: Array<ArgumentTypeToValueType<TypeT>>;
166+
}): NewTaskDefinitionBuilder<
167+
ExtendTaskArguments<NameT, TypeT, TaskArgumentsT>
168+
> {
144169
return this.#addPositionalArgument({
145170
...argConfig,
146171
isVariadic: true,
@@ -158,27 +183,36 @@ export class NewTaskDefinitionBuilderImplementation
158183
type: TaskDefinitionType.NEW_TASK,
159184
id: this.#id,
160185
description: this.#description,
161-
action: this.#action,
186+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
187+
-- The type of the action is narrowed in the setAction function to
188+
improve the argument types. Once the task is built, we use the more
189+
general type to avoid having to parameterize the NewTaskDefinition */
190+
action: this.#action as NewTaskActionFunction,
162191
options: this.#options,
163192
positionalArguments: this.#positionalArgs,
164193
};
165194
}
166195

167-
#addPositionalArgument<T extends ArgumentType>({
196+
#addPositionalArgument<
197+
NameT extends string,
198+
TypeT extends ArgumentType = ArgumentType.STRING,
199+
>({
168200
name,
169201
description = "",
170202
type,
171203
defaultValue,
172204
isVariadic,
173205
}: {
174-
name: string;
206+
name: NameT;
175207
description?: string;
176-
type?: T;
208+
type?: TypeT;
177209
defaultValue?:
178-
| ArgumentTypeToValueType<T>
179-
| Array<ArgumentTypeToValueType<T>>;
210+
| ArgumentTypeToValueType<TypeT>
211+
| Array<ArgumentTypeToValueType<TypeT>>;
180212
isVariadic: boolean;
181-
}): this {
213+
}): NewTaskDefinitionBuilder<
214+
ExtendTaskArguments<NameT, TypeT, TaskArgumentsT>
215+
> {
182216
const argumentType = type ?? ArgumentType.STRING;
183217

184218
const positionalArgDef = {
@@ -203,16 +237,17 @@ export class NewTaskDefinitionBuilderImplementation
203237
}
204238
}
205239

206-
export class TaskOverrideDefinitionBuilderImplementation
207-
implements TaskOverrideDefinitionBuilder
240+
export class TaskOverrideDefinitionBuilderImplementation<
241+
TaskArgumentsT extends TaskArguments = TaskArguments,
242+
> implements TaskOverrideDefinitionBuilder<TaskArgumentsT>
208243
{
209244
readonly #id: string[];
210245

211246
readonly #options: Record<string, OptionDefinition> = {};
212247

213248
#description?: string;
214249

215-
#action?: TaskOverrideActionFunction | string;
250+
#action?: TaskOverrideActionFunction<TaskArgumentsT> | string;
216251

217252
constructor(id: string | string[]) {
218253
validateId(id);
@@ -225,25 +260,32 @@ export class TaskOverrideDefinitionBuilderImplementation
225260
return this;
226261
}
227262

228-
public setAction(action: TaskOverrideActionFunction | string): this {
263+
public setAction(
264+
action: TaskOverrideActionFunction<TaskArgumentsT> | string,
265+
): this {
229266
validateAction(action);
230267

231268
this.#action = action;
232269

233270
return this;
234271
}
235272

236-
public addOption<T extends ArgumentType>({
273+
public addOption<
274+
NameT extends string,
275+
TypeT extends ArgumentType = ArgumentType.STRING,
276+
>({
237277
name,
238278
description = "",
239279
type,
240280
defaultValue,
241281
}: {
242-
name: string;
282+
name: NameT;
243283
description?: string;
244-
type?: T;
245-
defaultValue: ArgumentTypeToValueType<T>;
246-
}): this {
284+
type?: TypeT;
285+
defaultValue: ArgumentTypeToValueType<TypeT>;
286+
}): TaskOverrideDefinitionBuilder<
287+
ExtendTaskArguments<NameT, TypeT, TaskArgumentsT>
288+
> {
247289
const argumentType = type ?? ArgumentType.STRING;
248290

249291
const optionDefinition = {
@@ -264,7 +306,12 @@ export class TaskOverrideDefinitionBuilderImplementation
264306
return this;
265307
}
266308

267-
public addFlag(flagConfig: { name: string; description?: string }): this {
309+
public addFlag<NameT extends string>(flagConfig: {
310+
name: string;
311+
description?: string;
312+
}): TaskOverrideDefinitionBuilder<
313+
ExtendTaskArguments<NameT, ArgumentType.BOOLEAN, TaskArgumentsT>
314+
> {
268315
return this.addOption({
269316
...flagConfig,
270317
type: ArgumentType.BOOLEAN,
@@ -283,7 +330,11 @@ export class TaskOverrideDefinitionBuilderImplementation
283330
type: TaskDefinitionType.TASK_OVERRIDE,
284331
id: this.#id,
285332
description: this.#description,
286-
action: this.#action,
333+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
334+
-- The type of the action is narrowed in the setAction function to
335+
improve the argument types. Once the task is built, we use the more
336+
general type to avoid having to parameterize the TaskOverrideDefinition */
337+
action: this.#action as TaskOverrideActionFunction,
287338
options: this.#options,
288339
};
289340
}

0 commit comments

Comments
 (0)