Skip to content

Commit b328cac

Browse files
shlomiassafaciccarello
authored andcommitted
add the TypeOperatorType that represents an operator result on a type ("keyof") (#614)
1 parent 800730f commit b328cac

18 files changed

+336
-16
lines changed

examples/basic/src/classes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export class BaseClass implements INameInterface
7373
/**
7474
* This is an instance member of an internal class.
7575
*/
76-
private internalClass:InternalClass;
76+
private internalClass:InternalClass<keyof BaseClass>;
7777

7878

7979
constructor(name:string);
@@ -181,7 +181,7 @@ export class BaseClass implements INameInterface
181181
/**
182182
* This is an internal class, it is not exported.
183183
*/
184-
class InternalClass
184+
class InternalClass<TTT extends keyof BaseClass>
185185
{
186186
constructor(options:{name:string}) {
187187

src/lib/converter/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export { ReferenceConverter } from './reference';
99
export { ThisConverter } from './this';
1010
export { TupleConverter } from './tuple';
1111
export { TypeParameterConverter } from './type-parameter';
12+
export { TypeOperatorConverter } from './type-operator';
1213
export { UnionOrIntersectionConverter } from './union-or-intersection';
1314
export { UnknownConverter } from './unknown';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as ts from 'typescript';
2+
3+
import { TypeOperatorType } from '../../models/types/index';
4+
import { Component, ConverterTypeComponent, TypeNodeConverter } from '../components';
5+
import { Context } from '../context';
6+
7+
@Component({name: 'type:type-operator'})
8+
export class TypeOperatorConverter extends ConverterTypeComponent implements TypeNodeConverter<ts.Type, ts.TypeOperatorNode> {
9+
/**
10+
* we want to run before union
11+
*/
12+
priority = 50;
13+
14+
/**
15+
* Test whether this converter can handle the given TypeScript node.
16+
*/
17+
supportsNode(context: Context, node: ts.TypeOperatorNode, type: ts.Type): boolean {
18+
return !!(node.kind === ts.SyntaxKind.TypeOperator);
19+
}
20+
21+
/**
22+
* Interpret the given type operator node and convert it into a type representing keys of a type
23+
*
24+
* @param context The context object describing the current state the converter is in.
25+
* @param node The type operator node representing keys of a type.
26+
* @returns The type representing keys of a type.
27+
*/
28+
convertNode(context: Context, node: ts.TypeOperatorNode): TypeOperatorType {
29+
const target = this.owner.convertType(context, node.type);
30+
return new TypeOperatorType(target);
31+
}
32+
}

src/lib/models/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export { ReferenceType } from './reference';
66
export { ReflectionType } from './reflection';
77
export { StringLiteralType } from './string-literal';
88
export { TupleType } from './tuple';
9+
export { TypeOperatorType } from './type-operator';
910
export { TypeParameterType } from './type-parameter';
1011
export { UnionType } from './union';
1112
export { UnknownType } from './unknown';

src/lib/models/types/type-operator.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Type } from './abstract';
2+
3+
/**
4+
* Represents a type operator type.
5+
*
6+
* ~~~
7+
* class A {}
8+
* class B<T extends keyof A> {}
9+
* ~~~
10+
*/
11+
export class TypeOperatorType extends Type {
12+
/**
13+
* The type name identifier.
14+
*/
15+
readonly type: string = 'typeOperator';
16+
17+
target: Type;
18+
19+
// currently, there is only one type operator, this is always "keyof"
20+
// but, if more types will be added in the future we are ready.
21+
operator: 'keyof' = 'keyof';
22+
23+
constructor(target: Type) {
24+
super();
25+
this.target = target;
26+
}
27+
28+
/**
29+
* Clone this type.
30+
*
31+
* @return A clone of this type.
32+
*/
33+
clone(): Type {
34+
return new TypeOperatorType(this.target.clone());
35+
}
36+
37+
/**
38+
* Test whether this type equals the given type.
39+
*
40+
* @param type The type that should be checked for equality.
41+
* @returns TRUE if the given type equals this type, FALSE otherwise.
42+
*/
43+
equals(type: TypeOperatorType): boolean {
44+
if (!(type instanceof TypeOperatorType)) {
45+
return false;
46+
}
47+
48+
return type.target.equals(this.target);
49+
}
50+
51+
/**
52+
* Return a raw object representation of this type.
53+
*/
54+
toObject(): any {
55+
const result: any = super.toObject();
56+
result.operator = this.operator;
57+
result.target = this.target.toObject();
58+
return result;
59+
}
60+
61+
/**
62+
* Return a string representation of this type.
63+
*/
64+
toString() {
65+
return `keyof ${this.target.toString()}`;
66+
}
67+
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
{
2+
"id": 0,
3+
"name": "typedoc",
4+
"kind": 0,
5+
"flags": {},
6+
"children": [
7+
{
8+
"id": 1,
9+
"name": "\"type-operator\"",
10+
"kind": 1,
11+
"kindString": "External module",
12+
"flags": {
13+
"isExported": true
14+
},
15+
"originalName": "%BASE%/type-operator/type-operator.ts",
16+
"children": [
17+
{
18+
"id": 5,
19+
"name": "GenericClass",
20+
"kind": 128,
21+
"kindString": "Class",
22+
"flags": {
23+
"isExported": true
24+
},
25+
"typeParameter": [
26+
{
27+
"id": 6,
28+
"name": "T",
29+
"kind": 131072,
30+
"kindString": "Type parameter",
31+
"flags": {},
32+
"type": {
33+
"type": "typeOperator",
34+
"operator": "keyof",
35+
"target": {
36+
"type": "reference",
37+
"name": "TestClass"
38+
}
39+
}
40+
}
41+
],
42+
"children": [
43+
{
44+
"id": 7,
45+
"name": "c",
46+
"kind": 1024,
47+
"kindString": "Property",
48+
"flags": {
49+
"isExported": true
50+
},
51+
"sources": [
52+
{
53+
"fileName": "type-operator.ts",
54+
"line": 14,
55+
"character": 5
56+
}
57+
],
58+
"type": {
59+
"type": "typeParameter",
60+
"name": "T",
61+
"constraint": {
62+
"type": "typeOperator",
63+
"operator": "keyof",
64+
"target": {
65+
"type": "reference",
66+
"name": "TestClass"
67+
}
68+
}
69+
}
70+
}
71+
],
72+
"groups": [
73+
{
74+
"title": "Properties",
75+
"kind": 1024,
76+
"children": [
77+
7
78+
]
79+
}
80+
],
81+
"sources": [
82+
{
83+
"fileName": "type-operator.ts",
84+
"line": 13,
85+
"character": 25
86+
}
87+
]
88+
},
89+
{
90+
"id": 2,
91+
"name": "TestClass",
92+
"kind": 128,
93+
"kindString": "Class",
94+
"flags": {
95+
"isExported": true
96+
},
97+
"comment": {
98+
"shortText": "TestClass comment short text.",
99+
"text": "TestClass comment text.\n",
100+
"tags": [
101+
{
102+
"tag": "see",
103+
"text": "[[TestClass]] @ fixtures\n"
104+
}
105+
]
106+
},
107+
"children": [
108+
{
109+
"id": 3,
110+
"name": "a",
111+
"kind": 1024,
112+
"kindString": "Property",
113+
"flags": {
114+
"isExported": true
115+
},
116+
"sources": [
117+
{
118+
"fileName": "type-operator.ts",
119+
"line": 9,
120+
"character": 5
121+
}
122+
],
123+
"type": {
124+
"type": "intrinsic",
125+
"name": "string"
126+
}
127+
},
128+
{
129+
"id": 4,
130+
"name": "b",
131+
"kind": 1024,
132+
"kindString": "Property",
133+
"flags": {
134+
"isExported": true
135+
},
136+
"sources": [
137+
{
138+
"fileName": "type-operator.ts",
139+
"line": 10,
140+
"character": 5
141+
}
142+
],
143+
"type": {
144+
"type": "intrinsic",
145+
"name": "number"
146+
}
147+
}
148+
],
149+
"groups": [
150+
{
151+
"title": "Properties",
152+
"kind": 1024,
153+
"children": [
154+
3,
155+
4
156+
]
157+
}
158+
],
159+
"sources": [
160+
{
161+
"fileName": "type-operator.ts",
162+
"line": 8,
163+
"character": 22
164+
}
165+
]
166+
}
167+
],
168+
"groups": [
169+
{
170+
"title": "Classes",
171+
"kind": 128,
172+
"children": [
173+
5,
174+
2
175+
]
176+
}
177+
],
178+
"sources": [
179+
{
180+
"fileName": "type-operator.ts",
181+
"line": 1,
182+
"character": 0
183+
}
184+
]
185+
}
186+
],
187+
"groups": [
188+
{
189+
"title": "External modules",
190+
"kind": 1,
191+
"children": [
192+
1
193+
]
194+
}
195+
]
196+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* TestClass comment short text.
3+
*
4+
* TestClass comment text.
5+
*
6+
* @see [[TestClass]] @ fixtures
7+
*/
8+
export class TestClass {
9+
a: string;
10+
b: number;
11+
}
12+
13+
export class GenericClass<T extends keyof TestClass> {
14+
c: T;
15+
}

src/test/renderer/specs/classes/_classes_.baseclass.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ <h2>Properties</h2>
180180
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class tsd-is-private">
181181
<a name="internalclass" class="tsd-anchor"></a>
182182
<h3><span class="tsd-flag ts-flagPrivate">Private</span> internal<wbr>Class</h3>
183-
<div class="tsd-signature tsd-kind-icon">internal<wbr>Class<span class="tsd-signature-symbol">:</span> <a href="_classes_.internalclass.html" class="tsd-signature-type">InternalClass</a></div>
183+
<div class="tsd-signature tsd-kind-icon">internal<wbr>Class<span class="tsd-signature-symbol">:</span> <a href="_classes_.internalclass.html" class="tsd-signature-type">InternalClass</a><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">keyof BaseClass</span><span class="tsd-signature-symbol">&gt;</span></div>
184184
<aside class="tsd-sources">
185185
<ul>
186186
<li>Defined in <a href="https://github.com/sebastian-lenz/typedoc/blob/master/examples/basic/src/classes.ts#L76">classes.ts:76</a></li>
@@ -560,7 +560,7 @@ <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">string</s
560560
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter">
561561
<a href="_classes_.genericclass.html" class="tsd-kind-icon">Generic<wbr>Class</a>
562562
</li>
563-
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-is-not-exported">
563+
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter tsd-is-not-exported">
564564
<a href="_classes_.internalclass.html" class="tsd-kind-icon">Internal<wbr>Class</a>
565565
</li>
566566
<li class=" tsd-kind-class tsd-parent-kind-external-module">

src/test/renderer/specs/classes/_classes_.genericclass.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</spa
404404
</li>
405405
</ul>
406406
<ul class="after-current">
407-
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-is-not-exported">
407+
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter tsd-is-not-exported">
408408
<a href="_classes_.internalclass.html" class="tsd-kind-icon">Internal<wbr>Class</a>
409409
</li>
410410
<li class=" tsd-kind-class tsd-parent-kind-external-module">

0 commit comments

Comments
 (0)