-
Notifications
You must be signed in to change notification settings - Fork 677
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Convert conditional types, indexed access types
closes #1150 closes #831 * Added test for conditional types. i.e. `X extends A ? B : C` Currently results in { "type": "unknown", "name": "X extends A ? B : C" } See #831 * Add support for conditional type. * add a test for infer * feat: Add support for indexed access types Co-authored-by: Adrian Leonhard <adrianleonhard@gmail.com>
- Loading branch information
Showing
23 changed files
with
982 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import * as ts from 'typescript'; | ||
|
||
import { ConditionalType, Type } from '../../models/types'; | ||
import { Component, ConverterTypeComponent, TypeConverter } from '../components'; | ||
import { Context } from '../context'; | ||
|
||
@Component({name: 'type:conditional'}) | ||
export class ConditionalConverter extends ConverterTypeComponent implements TypeConverter<ts.ConditionalType, ts.ConditionalTypeNode> { | ||
/** | ||
* Test whether this converter can handle the given TypeScript node. | ||
*/ | ||
supportsNode(context: Context, node: ts.ConditionalTypeNode): boolean { | ||
return node.kind === ts.SyntaxKind.ConditionalType; | ||
} | ||
|
||
/** | ||
* Test whether this converter can handle the given TypeScript type. | ||
*/ | ||
supportsType(context: Context, type: ts.ConditionalType): boolean { | ||
return !!(type.flags & ts.TypeFlags.Conditional); | ||
} | ||
|
||
/** | ||
* Convert the given conditional type node to its type reflection. | ||
* | ||
* This is a node based converter, see [[convertType]] for the type equivalent. | ||
* | ||
* @param context The context object describing the current state the converter is in. | ||
* @param node The conditional or intersection type node that should be converted. | ||
* @returns The type reflection representing the given conditional type node. | ||
*/ | ||
convertNode(context: Context, node: ts.ConditionalTypeNode): ConditionalType | undefined { | ||
const types = this.owner.convertTypes(context, [node.checkType, node.extendsType, node.trueType, node.falseType]); | ||
if (types.length !== 4) { | ||
return undefined; | ||
} | ||
return new ConditionalType(...types as [Type, Type, Type, Type]); | ||
} | ||
|
||
/** | ||
* Convert the given conditional type to its type reflection. | ||
* | ||
* This is a type based converter, see [[convertNode]] for the node equivalent. | ||
* | ||
* @param context The context object describing the current state the converter is in. | ||
* @param type The conditional type that should be converted. | ||
* @returns The type reflection representing the given conditional type. | ||
*/ | ||
convertType(context: Context, type: ts.ConditionalType): ConditionalType | undefined { | ||
const types = this.owner.convertTypes(context, [], [type.checkType, type.extendsType, type.resolvedTrueType, type.resolvedFalseType]); | ||
if (types.length !== 4) { | ||
return undefined; | ||
} | ||
return new ConditionalType(...types as [Type, Type, Type, Type]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import * as ts from 'typescript'; | ||
|
||
import { Type, IndexedAccessType } from '../../models/index'; | ||
import { | ||
Component, | ||
ConverterTypeComponent, | ||
TypeNodeConverter | ||
} from '../components'; | ||
import { Context } from '../context'; | ||
|
||
@Component({ name: 'type:indexed-access' }) | ||
export class IndexedAccessConverter extends ConverterTypeComponent | ||
implements TypeNodeConverter<ts.Type, ts.IndexedAccessTypeNode> { | ||
/** | ||
* Test whether this converter can handle the given TypeScript node. | ||
*/ | ||
supportsNode(context: Context, node: ts.TypeNode) { | ||
return ts.isIndexedAccessTypeNode(node); | ||
} | ||
|
||
convertNode(context: Context, node: ts.IndexedAccessTypeNode): Type | undefined { | ||
const objectType = this.owner.convertType(context, node.objectType); | ||
if (!objectType) { return; } | ||
const indexType = this.owner.convertType(context, node.indexType); | ||
if (!indexType) { return; } | ||
return new IndexedAccessType(objectType, indexType); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import * as ts from 'typescript'; | ||
|
||
import { InferredType } from '../../models/types'; | ||
import { Component, ConverterTypeComponent, TypeNodeConverter } from '../components'; | ||
import { Context } from '../context'; | ||
|
||
@Component({name: 'type:inferred'}) | ||
export class InferredConverter extends ConverterTypeComponent implements TypeNodeConverter<ts.Type, ts.InferTypeNode> { | ||
/** | ||
* Test whether this converter can handle the given TypeScript node. | ||
*/ | ||
supportsNode(_context: Context, node: ts.TypeNode): boolean { | ||
return ts.isInferTypeNode(node); | ||
} | ||
|
||
/** | ||
* Convert the given conditional type node to its type reflection. | ||
* | ||
* This is a node based converter, see [[convertType]] for the type equivalent. | ||
* | ||
* @param context The context object describing the current state the converter is in. | ||
* @param node The conditional or intersection type node that should be converted. | ||
* @returns The type reflection representing the given conditional type node. | ||
*/ | ||
convertNode(context: Context, node: ts.InferTypeNode): InferredType | undefined { | ||
return new InferredType(node.typeParameter.getText()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { Type } from './abstract'; | ||
|
||
/** | ||
* Represents a conditional type. | ||
* | ||
* ~~~ | ||
* let value: C extends E ? T : F; | ||
* let value2: Check extends Extends ? True : False; | ||
* ~~~ | ||
*/ | ||
export class ConditionalType extends Type { | ||
/** | ||
* The type name identifier. | ||
*/ | ||
readonly type: string = 'conditional'; | ||
|
||
constructor( | ||
public checkType: Type, | ||
public extendsType: Type, | ||
public trueType: Type, | ||
public falseType: Type | ||
) { | ||
super(); | ||
} | ||
|
||
/** | ||
* Clone this type. | ||
* | ||
* @return A clone of this type. | ||
*/ | ||
clone(): Type { | ||
return new ConditionalType(this.checkType, this.extendsType, this.trueType, this.falseType); | ||
} | ||
|
||
/** | ||
* 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: any): boolean { | ||
if (!(type instanceof ConditionalType)) { | ||
return false; | ||
} | ||
return this.checkType.equals(type.checkType) && | ||
this.extendsType.equals(type.extendsType) && | ||
this.trueType.equals(type.trueType) && | ||
this.falseType.equals(type.falseType); | ||
} | ||
|
||
/** | ||
* Return a raw object representation of this type. | ||
* @deprecated Use serializers instead | ||
*/ | ||
toObject(): any { | ||
const result: any = super.toObject(); | ||
|
||
result.checkType = this.checkType.toObject(); | ||
result.extendsType = this.extendsType.toObject(); | ||
result.trueType = this.trueType.toObject(); | ||
result.falseType = this.falseType.toObject(); | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* Return a string representation of this type. | ||
*/ | ||
toString() { | ||
return this.checkType + ' extends ' + this.extendsType + ' ? ' + this.trueType + ' : ' + this.falseType; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { Type } from './index'; | ||
|
||
/** | ||
* Represents an indexed access type. | ||
*/ | ||
export class IndexedAccessType extends Type { | ||
/** | ||
* The type name identifier. | ||
*/ | ||
readonly type = 'indexedAccess'; | ||
|
||
/** | ||
* Create a new TupleType instance. | ||
* | ||
* @param elementType The type of the array's elements. | ||
*/ | ||
constructor(public objectType: Type, public indexType: Type) { | ||
super(); | ||
} | ||
|
||
/** | ||
* Clone this type. | ||
* | ||
* @return A clone of this type. | ||
*/ | ||
clone(): Type { | ||
return new IndexedAccessType(this.objectType, this.indexType); | ||
} | ||
|
||
/** | ||
* 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: Type): boolean { | ||
if (!(type instanceof IndexedAccessType)) { | ||
return false; | ||
} | ||
return type.objectType.equals(this.objectType) && type.indexType.equals(this.indexType); | ||
} | ||
|
||
/** | ||
* Return a raw object representation of this type. | ||
* @deprecated Use serializers instead | ||
*/ | ||
toObject(): any { | ||
return { | ||
...super.toObject(), | ||
objectType: this.objectType.toObject(), | ||
indexType: this.indexType.toObject() | ||
}; | ||
} | ||
|
||
/** | ||
* Return a string representation of this type. | ||
*/ | ||
toString() { | ||
return `${this.objectType.toString()}[${this.indexType.toString()}]`; | ||
} | ||
} |
Oops, something went wrong.