Skip to content

Commit b4ac0d9

Browse files
add loose-vars option to wrangler types
1 parent 376a46b commit b4ac0d9

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
@@ -603,6 +603,35 @@ describe("generateTypes()", () => {
603603
`);
604604
});
605605

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

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

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

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

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

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

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

@@ -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)