Skip to content

Commit 2df0bea

Browse files
authored
Support indexed access (#532)
1 parent fca5cef commit 2df0bea

File tree

7 files changed

+159
-2
lines changed

7 files changed

+159
-2
lines changed

Diff for: api.md

+39
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,45 @@ export interface MyObject {
10321032
```
10331033

10341034

1035+
## [key-in-key-of-multi](./test/programs/key-in-key-of-multi)
1036+
1037+
```ts
1038+
type Util = {
1039+
utilKey1: {
1040+
utilDeepKey11: string;
1041+
utilDeepKey12: number;
1042+
};
1043+
utilKey2: {
1044+
utilDeepKey21: boolean;
1045+
utilDeepKey22: null;
1046+
};
1047+
};
1048+
1049+
export type Main = {
1050+
[Key in keyof Util]: {
1051+
[key: string]: Util[Key];
1052+
};
1053+
};
1054+
```
1055+
1056+
1057+
## [key-in-key-of-single](./test/programs/key-in-key-of-single)
1058+
1059+
```ts
1060+
type Util = {
1061+
utilKey: {
1062+
utilDeepKey: string;
1063+
};
1064+
};
1065+
1066+
export type Main = {
1067+
[Key in keyof Util]: {
1068+
[key: string]: Util[Key];
1069+
};
1070+
};
1071+
```
1072+
1073+
10351074
## [map-types](./test/programs/map-types)
10361075

10371076
```ts

Diff for: test/programs/key-in-key-of-multi/main.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type Util = {
2+
utilKey1: {
3+
utilDeepKey11: string;
4+
utilDeepKey12: number;
5+
};
6+
utilKey2: {
7+
utilDeepKey21: boolean;
8+
utilDeepKey22: null;
9+
};
10+
};
11+
12+
export type Main = {
13+
[Key in keyof Util]: {
14+
[key: string]: Util[Key];
15+
};
16+
};

Diff for: test/programs/key-in-key-of-multi/schema.json

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"properties": {
4+
"utilKey1": {
5+
"additionalProperties": {
6+
"properties": {
7+
"utilDeepKey11": {
8+
"type": "string"
9+
},
10+
"utilDeepKey12": {
11+
"type": "number"
12+
}
13+
},
14+
"required": [
15+
"utilDeepKey11",
16+
"utilDeepKey12"
17+
],
18+
"type": "object"
19+
},
20+
"type": "object"
21+
},
22+
"utilKey2": {
23+
"additionalProperties": {
24+
"properties": {
25+
"utilDeepKey21": {
26+
"type": "boolean"
27+
},
28+
"utilDeepKey22": {
29+
"type": "null"
30+
}
31+
},
32+
"required": [
33+
"utilDeepKey21",
34+
"utilDeepKey22"
35+
],
36+
"type": "object"
37+
},
38+
"type": "object"
39+
}
40+
},
41+
"required": [
42+
"utilKey1",
43+
"utilKey2"
44+
],
45+
"type": "object"
46+
}
47+

Diff for: test/programs/key-in-key-of-single/main.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type Util = {
2+
utilKey: {
3+
utilDeepKey: string;
4+
};
5+
};
6+
7+
export type Main = {
8+
[Key in keyof Util]: {
9+
[key: string]: Util[Key];
10+
};
11+
};

Diff for: test/programs/key-in-key-of-single/schema.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"properties": {
5+
"utilKey": {
6+
"type": "object",
7+
"additionalProperties": {
8+
"type": "object",
9+
"properties": {
10+
"utilDeepKey": {
11+
"type": "string"
12+
}
13+
},
14+
"required": [
15+
"utilDeepKey"
16+
]
17+
}
18+
}
19+
},
20+
"required": [
21+
"utilKey"
22+
]
23+
}

Diff for: test/schema.test.ts

+5
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,11 @@ describe("schema", () => {
438438
describe("typeof globalThis", () => {
439439
assertSchema("type-globalThis", "Test");
440440
});
441+
442+
describe("key in key of", () => {
443+
assertSchema("key-in-key-of-single", "Main");
444+
assertSchema("key-in-key-of-multi", "Main");
445+
});
441446
});
442447

443448
describe("tsconfig.json", () => {

Diff for: typescript-json-schema.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -1070,8 +1070,24 @@ export class JsonSchemaGenerator {
10701070
}
10711071

10721072
const typ = this.tc.getTypeAtLocation(indexSignature.type!);
1073-
const def = this.getTypeDefinition(typ, undefined, "anyOf");
1074-
1073+
let def: Definition | undefined;
1074+
if (typ.flags & ts.TypeFlags.IndexedAccess) {
1075+
const targetName: string = (<any>clazzType).mapper?.target?.value;
1076+
const indexedAccessType = <ts.IndexedAccessType>typ;
1077+
const symbols: Map<string, ts.Symbol> = (<any>indexedAccessType.objectType).members;
1078+
const targetSymbol = symbols?.get(targetName);
1079+
1080+
if (targetSymbol) {
1081+
const targetNode = targetSymbol.getDeclarations()![0];
1082+
const targetDef = this.getDefinitionForProperty(targetSymbol, targetNode);
1083+
if (targetDef) {
1084+
def = targetDef;
1085+
}
1086+
}
1087+
}
1088+
if (!def) {
1089+
def = this.getTypeDefinition(typ, undefined, "anyOf");
1090+
}
10751091
if (isStringIndexed) {
10761092
definition.type = "object";
10771093
definition.additionalProperties = def;

0 commit comments

Comments
 (0)