Skip to content

Commit bed1a3a

Browse files
add loose-vars option to wrangler types
1 parent ebf7bf5 commit bed1a3a

File tree

3 files changed

+153
-38
lines changed

3 files changed

+153
-38
lines changed

.changeset/unlucky-timers-sort.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
add `loose-vars` option to `wrangler types`
6+
7+
add a new `--loose-vars` option to `wrangler types` that developers can use to get more
8+
loose types for their variables instead of literal and union types
9+
10+
these more loose types can be useful when developers change often their `vars` values,
11+
even more so when multiple environments are involved
12+
13+
## Example
14+
15+
With a toml containing:
16+
17+
```toml
18+
[vars]
19+
MY_VARIABLE = "production_value"
20+
MY_NUMBERS = [1, 2, 3]
21+
22+
[env.staging.vars]
23+
MY_VARIABLE = "staging_value"
24+
MY_NUMBERS = [7, 8, 9]
25+
```
26+
27+
the `wrangler types` command would generate the following interface:
28+
29+
```
30+
interface Env {
31+
MY_VARIABLE: "production_value" | "staging_value";
32+
MY_NUMBERS: [1,2,3] | [7,8,9];
33+
}
34+
```
35+
36+
while `wrangler types --loose-vars` would instead generate:
37+
38+
```
39+
interface Env {
40+
MY_VARIABLE: string;
41+
MY_NUMBERS: number[];
42+
}
43+
```
44+
45+
(allowing the developer to easily change their toml variables without the
46+
risk of braking typescript types)

packages/wrangler/src/__tests__/type-generation.test.ts

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,35 @@ describe("generateTypes()", () => {
602602
`);
603603
});
604604

605+
it("should respect the loose-vars option", async () => {
606+
fs.writeFileSync(
607+
"./wrangler.toml",
608+
TOML.stringify({
609+
vars: {
610+
varStr: "A from wrangler toml",
611+
varArrNum: [1, 2, 3],
612+
varArrMix: [1, "two", 3, true],
613+
varObj: { test: true },
614+
},
615+
} as TOML.JsonMap),
616+
"utf-8"
617+
);
618+
619+
await runWrangler("types --loose-vars");
620+
621+
expect(std.out).toMatchInlineSnapshot(`
622+
"Generating project types...
623+
624+
interface Env {
625+
varStr: string;
626+
varArrNum: number[];
627+
varArrMix: (boolean|number|string)[];
628+
varObj: object;
629+
}
630+
"
631+
`);
632+
});
633+
605634
it("should override vars with secrets", async () => {
606635
fs.writeFileSync(
607636
"./wrangler.toml",
@@ -634,48 +663,68 @@ describe("generateTypes()", () => {
634663
`);
635664
});
636665

637-
it("should produce unions where appropriate for vars present in multiple environments", async () => {
638-
fs.writeFileSync(
639-
"./wrangler.toml",
640-
TOML.stringify({
641-
vars: {
642-
MY_VAR: "a var",
643-
MY_VAR_A: "A (dev)",
644-
MY_VAR_B: { value: "B (dev)" },
645-
MY_VAR_C: ["a", "b", "c"],
646-
},
647-
env: {
648-
production: {
649-
vars: {
650-
MY_VAR: "a var",
651-
MY_VAR_A: "A (prod)",
652-
MY_VAR_B: { value: "B (prod)" },
653-
MY_VAR_C: [1, 2, 3],
654-
},
666+
describe("vars present in multiple environments", () => {
667+
beforeEach(() => {
668+
fs.writeFileSync(
669+
"./wrangler.toml",
670+
TOML.stringify({
671+
vars: {
672+
MY_VAR: "a var",
673+
MY_VAR_A: "A (dev)",
674+
MY_VAR_B: { value: "B (dev)" },
675+
MY_VAR_C: ["a", "b", "c"],
655676
},
656-
staging: {
657-
vars: {
658-
MY_VAR_A: "A (stag)",
677+
env: {
678+
production: {
679+
vars: {
680+
MY_VAR: "a var",
681+
MY_VAR_A: "A (prod)",
682+
MY_VAR_B: { value: "B (prod)" },
683+
MY_VAR_C: [1, 2, 3],
684+
},
685+
},
686+
staging: {
687+
vars: {
688+
MY_VAR_A: "A (stag)",
689+
},
659690
},
660691
},
661-
},
662-
} as TOML.JsonMap),
663-
"utf-8"
664-
);
692+
} as TOML.JsonMap),
693+
"utf-8"
694+
);
695+
});
665696

666-
await runWrangler("types");
697+
it("should produce string and union types for variables (default)", async () => {
698+
await runWrangler("types");
667699

668-
expect(std.out).toMatchInlineSnapshot(`
669-
"Generating project types...
700+
expect(std.out).toMatchInlineSnapshot(`
701+
"Generating project types...
670702
671-
interface Env {
672-
MY_VAR: \\"a var\\";
673-
MY_VAR_A: \\"A (dev)\\" | \\"A (prod)\\" | \\"A (stag)\\";
674-
MY_VAR_C: [\\"a\\",\\"b\\",\\"c\\"] | [1,2,3];
675-
MY_VAR_B: {\\"value\\":\\"B (dev)\\"} | {\\"value\\":\\"B (prod)\\"};
676-
}
677-
"
678-
`);
703+
interface Env {
704+
MY_VAR: \\"a var\\";
705+
MY_VAR_A: \\"A (dev)\\" | \\"A (prod)\\" | \\"A (stag)\\";
706+
MY_VAR_C: [\\"a\\",\\"b\\",\\"c\\"] | [1,2,3];
707+
MY_VAR_B: {\\"value\\":\\"B (dev)\\"} | {\\"value\\":\\"B (prod)\\"};
708+
}
709+
"
710+
`);
711+
});
712+
713+
it("should produce loose types for variables (with --loose-vars)", async () => {
714+
await runWrangler("types --loose-vars=true");
715+
716+
expect(std.out).toMatchInlineSnapshot(`
717+
"Generating project types...
718+
719+
interface Env {
720+
MY_VAR: string;
721+
MY_VAR_A: string;
722+
MY_VAR_C: string[] | number[];
723+
MY_VAR_B: object;
724+
}
725+
"
726+
`);
727+
});
679728
});
680729

681730
describe("customization", () => {

packages/wrangler/src/type-generation/index.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ export function typesOptions(yargs: CommonYargsArgv) {
3838
type: "string",
3939
describe: "The path of the generated runtime types file",
4040
demandOption: false,
41+
})
42+
.option("loose-vars", {
43+
type: "boolean",
44+
default: false,
45+
describe:
46+
'Generate "loose"/generic types instead of literal and union types for variables',
4147
});
4248
}
4349

@@ -147,7 +153,8 @@ export async function typesHandler(
147153
configBindingsWithSecrets,
148154
config,
149155
envInterface,
150-
outputPath
156+
outputPath,
157+
args.looseVars
151158
);
152159
}
153160

@@ -245,7 +252,8 @@ async function generateTypes(
245252
configToDTS: ConfigToDTS,
246253
config: Config,
247254
envInterface: string,
248-
outputPath: string
255+
outputPath: string,
256+
looseVars: boolean
249257
) {
250258
const configContainsEntrypoint =
251259
config.main !== undefined || !!config.site?.["entry-point"];
@@ -296,6 +304,18 @@ async function generateTypes(
296304
varInfo
297305
.map(({ value }) => value)
298306
.map((varValue) => {
307+
if (looseVars) {
308+
if (Array.isArray(varValue)) {
309+
const typesInArray = [
310+
...new Set(varValue.map((item) => typeof item)),
311+
].sort();
312+
if (typesInArray.length === 1) {
313+
return `${typesInArray[0]}[]`;
314+
}
315+
return `(${typesInArray.join("|")})[]`;
316+
}
317+
return typeof varValue;
318+
}
299319
if (
300320
typeof varValue === "string" ||
301321
typeof varValue === "number" ||

0 commit comments

Comments
 (0)