Skip to content

Commit b3e6070

Browse files
authored
fix(typescript): make index signatures readonly (#3504)
* fix(typescript): make index signatures readonly * fix(flow): emit covariant readonly properties (#3510)
1 parent 4766d88 commit b3e6070

3 files changed

Lines changed: 74 additions & 3 deletions

File tree

‎packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer {
135135
(_classType) => panic("We handled this above"),
136136
(mapType) =>
137137
singleWord([
138-
"{ [key: string]: ",
138+
"{ ",
139+
this._tsFlowOptions.readonly
140+
? this.targetLanguage.name === "flow"
141+
? "+"
142+
: "readonly "
143+
: "",
144+
"[key: string]: ",
139145
this.sourceFor(mapType.values).source,
140146
" }",
141147
]),
@@ -184,7 +190,8 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer {
184190

185191
if (this._tsFlowOptions.readonly) {
186192
propertyName = modifySource(
187-
(_propertyName) => `readonly ${_propertyName}`,
193+
(_propertyName) =>
194+
`${this.targetLanguage.name === "flow" ? "+" : "readonly "}${_propertyName}`,
188195
propertyName,
189196
);
190197
}
@@ -228,7 +235,9 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer {
228235

229236
this.emitTable([
230237
[
231-
"[property: string]",
238+
this._tsFlowOptions.readonly
239+
? `${this.targetLanguage.name === "flow" ? "+" : "readonly "}[property: string]`
240+
: "[property: string]",
232241
": ",
233242
multiWord(" | ", ...indexTypes).source,
234243
";",

‎test/languages.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,8 @@ export const TypeScriptLanguage: Language = {
10001000
{ "acronym-style": "pascal" },
10011001
{ converters: "all-objects" },
10021002
{ readonly: "true" },
1003+
["number-map.json", { readonly: "true" }],
1004+
["class-with-additional.schema", { readonly: "true" }],
10031005
// The default is prefer-unions=true; this keeps the TypeScript
10041006
// enum code path covered.
10051007
{ "prefer-unions": "false" },
@@ -1120,6 +1122,9 @@ export const FlowLanguage: Language = {
11201122
// Flow output.
11211123
{ "prefer-unions": "false" },
11221124
{ "prefer-unknown": "false" },
1125+
["simple-object.json", { readonly: "true" }],
1126+
["number-map.json", { readonly: "true" }],
1127+
["class-with-additional.schema", { readonly: "true" }],
11231128
],
11241129
sourceFiles: ["src/language/Flow/index.ts"],
11251130
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { describe, expect, test } from "vitest";
2+
3+
import {
4+
InputData,
5+
JSONSchemaInput,
6+
quicktype,
7+
} from "../../packages/quicktype-core/src/index.js";
8+
9+
describe("TypeScript readonly", () => {
10+
test("applies to index signatures", async () => {
11+
const input = new JSONSchemaInput(undefined);
12+
await input.addSource({
13+
name: "TopLevel",
14+
schema: JSON.stringify({
15+
type: "object",
16+
properties: { fixed: { type: "string" } },
17+
required: ["fixed"],
18+
additionalProperties: { type: "string" },
19+
}),
20+
});
21+
const inputData = new InputData();
22+
inputData.addInput(input);
23+
24+
const result = await quicktype({
25+
inputData,
26+
lang: "typescript",
27+
rendererOptions: { readonly: "true" },
28+
});
29+
30+
expect(result.lines.join("\n")).toContain(
31+
"readonly [property: string]: string;",
32+
);
33+
});
34+
35+
test("applies to map types", async () => {
36+
const input = new JSONSchemaInput(undefined);
37+
await input.addSource({
38+
name: "TopLevel",
39+
schema: JSON.stringify({
40+
type: "object",
41+
additionalProperties: { type: "string" },
42+
}),
43+
});
44+
const inputData = new InputData();
45+
inputData.addInput(input);
46+
47+
const result = await quicktype({
48+
inputData,
49+
lang: "typescript",
50+
rendererOptions: { readonly: "true" },
51+
});
52+
53+
expect(result.lines.join("\n")).toContain(
54+
"{ readonly [key: string]: string }",
55+
);
56+
});
57+
});

0 commit comments

Comments
 (0)