Skip to content

add the TypeOperatorType that represents an op result on a type ("keyof") #614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/basic/src/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class BaseClass implements INameInterface
/**
* This is an instance member of an internal class.
*/
private internalClass:InternalClass;
private internalClass:InternalClass<keyof BaseClass>;


constructor(name:string);
Expand Down Expand Up @@ -181,7 +181,7 @@ export class BaseClass implements INameInterface
/**
* This is an internal class, it is not exported.
*/
class InternalClass
class InternalClass<TTT extends keyof BaseClass>
{
constructor(options:{name:string}) {

Expand Down
1 change: 1 addition & 0 deletions src/lib/converter/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export { ReferenceConverter } from './reference';
export { ThisConverter } from './this';
export { TupleConverter } from './tuple';
export { TypeParameterConverter } from './type-parameter';
export { TypeOperatorConverter } from './type-operator';
export { UnionOrIntersectionConverter } from './union-or-intersection';
export { UnknownConverter } from './unknown';
32 changes: 32 additions & 0 deletions src/lib/converter/types/type-operator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as ts from 'typescript';

import { TypeOperatorType } from '../../models/types/index';
import { Component, ConverterTypeComponent, TypeNodeConverter } from '../components';
import { Context } from '../context';

@Component({name: 'type:type-operator'})
export class TypeOperatorConverter extends ConverterTypeComponent implements TypeNodeConverter<ts.Type, ts.TypeOperatorNode> {
/**
* we want to run before union
*/
priority = 50;

/**
* Test whether this converter can handle the given TypeScript node.
*/
supportsNode(context: Context, node: ts.TypeOperatorNode, type: ts.Type): boolean {
return !!(node.kind === ts.SyntaxKind.TypeOperator);
}

/**
* Interpret the given type operator node and convert it into a type representing keys of a type
*
* @param context The context object describing the current state the converter is in.
* @param node The type operator node representing keys of a type.
* @returns The type representing keys of a type.
*/
convertNode(context: Context, node: ts.TypeOperatorNode): TypeOperatorType {
const target = this.owner.convertType(context, node.type);
return new TypeOperatorType(target);
}
}
1 change: 1 addition & 0 deletions src/lib/models/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { ReferenceType } from './reference';
export { ReflectionType } from './reflection';
export { StringLiteralType } from './string-literal';
export { TupleType } from './tuple';
export { TypeOperatorType } from './type-operator';
export { TypeParameterType } from './type-parameter';
export { UnionType } from './union';
export { UnknownType } from './unknown';
67 changes: 67 additions & 0 deletions src/lib/models/types/type-operator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Type } from './abstract';

/**
* Represents a type operator type.
*
* ~~~
* class A {}
* class B<T extends keyof A> {}
* ~~~
*/
export class TypeOperatorType extends Type {
/**
* The type name identifier.
*/
readonly type: string = 'typeOperator';

target: Type;

// currently, there is only one type operator, this is always "keyof"
// but, if more types will be added in the future we are ready.
operator: 'keyof' = 'keyof';

constructor(target: Type) {
super();
this.target = target;
}

/**
* Clone this type.
*
* @return A clone of this type.
*/
clone(): Type {
return new TypeOperatorType(this.target.clone());
}

/**
* Test whether this type equals the given type.
*
* @param type The type that should be checked for equality.
* @returns TRUE if the given type equals this type, FALSE otherwise.
*/
equals(type: TypeOperatorType): boolean {
if (!(type instanceof TypeOperatorType)) {
return false;
}

return type.target.equals(this.target);
}

/**
* Return a raw object representation of this type.
*/
toObject(): any {
const result: any = super.toObject();
result.operator = this.operator;
result.target = this.target.toObject();
return result;
}

/**
* Return a string representation of this type.
*/
toString() {
return `keyof ${this.target.toString()}`;
}
}
196 changes: 196 additions & 0 deletions src/test/converter/type-operator/specs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"id": 0,
"name": "typedoc",
"kind": 0,
"flags": {},
"children": [
{
"id": 1,
"name": "\"type-operator\"",
"kind": 1,
"kindString": "External module",
"flags": {
"isExported": true
},
"originalName": "%BASE%/type-operator/type-operator.ts",
"children": [
{
"id": 5,
"name": "GenericClass",
"kind": 128,
"kindString": "Class",
"flags": {
"isExported": true
},
"typeParameter": [
{
"id": 6,
"name": "T",
"kind": 131072,
"kindString": "Type parameter",
"flags": {},
"type": {
"type": "typeOperator",
"operator": "keyof",
"target": {
"type": "reference",
"name": "TestClass"
}
}
}
],
"children": [
{
"id": 7,
"name": "c",
"kind": 1024,
"kindString": "Property",
"flags": {
"isExported": true
},
"sources": [
{
"fileName": "type-operator.ts",
"line": 14,
"character": 5
}
],
"type": {
"type": "typeParameter",
"name": "T",
"constraint": {
"type": "typeOperator",
"operator": "keyof",
"target": {
"type": "reference",
"name": "TestClass"
}
}
}
}
],
"groups": [
{
"title": "Properties",
"kind": 1024,
"children": [
7
]
}
],
"sources": [
{
"fileName": "type-operator.ts",
"line": 13,
"character": 25
}
]
},
{
"id": 2,
"name": "TestClass",
"kind": 128,
"kindString": "Class",
"flags": {
"isExported": true
},
"comment": {
"shortText": "TestClass comment short text.",
"text": "TestClass comment text.\n",
"tags": [
{
"tag": "see",
"text": "[[TestClass]] @ fixtures\n"
}
]
},
"children": [
{
"id": 3,
"name": "a",
"kind": 1024,
"kindString": "Property",
"flags": {
"isExported": true
},
"sources": [
{
"fileName": "type-operator.ts",
"line": 9,
"character": 5
}
],
"type": {
"type": "intrinsic",
"name": "string"
}
},
{
"id": 4,
"name": "b",
"kind": 1024,
"kindString": "Property",
"flags": {
"isExported": true
},
"sources": [
{
"fileName": "type-operator.ts",
"line": 10,
"character": 5
}
],
"type": {
"type": "intrinsic",
"name": "number"
}
}
],
"groups": [
{
"title": "Properties",
"kind": 1024,
"children": [
3,
4
]
}
],
"sources": [
{
"fileName": "type-operator.ts",
"line": 8,
"character": 22
}
]
}
],
"groups": [
{
"title": "Classes",
"kind": 128,
"children": [
5,
2
]
}
],
"sources": [
{
"fileName": "type-operator.ts",
"line": 1,
"character": 0
}
]
}
],
"groups": [
{
"title": "External modules",
"kind": 1,
"children": [
1
]
}
]
}
15 changes: 15 additions & 0 deletions src/test/converter/type-operator/type-operator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* TestClass comment short text.
*
* TestClass comment text.
*
* @see [[TestClass]] @ fixtures
*/
export class TestClass {
a: string;
b: number;
}

export class GenericClass<T extends keyof TestClass> {
c: T;
}
4 changes: 2 additions & 2 deletions src/test/renderer/specs/classes/_classes_.baseclass.html
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ <h2>Properties</h2>
<section class="tsd-panel tsd-member tsd-kind-property tsd-parent-kind-class tsd-is-private">
<a name="internalclass" class="tsd-anchor"></a>
<h3><span class="tsd-flag ts-flagPrivate">Private</span> internal<wbr>Class</h3>
<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>
<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>
<aside class="tsd-sources">
<ul>
<li>Defined in <a href="https://github.com/sebastian-lenz/typedoc/blob/master/examples/basic/src/classes.ts#L76">classes.ts:76</a></li>
Expand Down Expand Up @@ -560,7 +560,7 @@ <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">string</s
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter">
<a href="_classes_.genericclass.html" class="tsd-kind-icon">Generic<wbr>Class</a>
</li>
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-is-not-exported">
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter tsd-is-not-exported">
<a href="_classes_.internalclass.html" class="tsd-kind-icon">Internal<wbr>Class</a>
</li>
<li class=" tsd-kind-class tsd-parent-kind-external-module">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ <h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</spa
</li>
</ul>
<ul class="after-current">
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-is-not-exported">
<li class=" tsd-kind-class tsd-parent-kind-external-module tsd-has-type-parameter tsd-is-not-exported">
<a href="_classes_.internalclass.html" class="tsd-kind-icon">Internal<wbr>Class</a>
</li>
<li class=" tsd-kind-class tsd-parent-kind-external-module">
Expand Down
Loading