Add support for type aliases, restructure

This commit is contained in:
Jerko Steiner 2019-08-12 21:32:09 +07:00
parent d1072031d6
commit e3232882aa
2 changed files with 133 additions and 135 deletions

View File

@ -26,6 +26,8 @@ export interface ITyped<T> {
} }
type AorB = 'A' | 'B' type AorB = 'A' | 'B'
/* tslint:disable-next-line */
type Param<T> = {t: T}
export class Person { export class Person {
readonly name!: Name readonly name!: Name
@ -54,4 +56,5 @@ export class Typed<A, B extends 'singleVal', C = 'defVal'> {
b!: ITyped<B> b!: ITyped<B>
c!: ITyped<C> c!: ITyped<C>
d!: ITyped<A> | ITyped<B> d!: ITyped<A> | ITyped<B>
e!: Param<Company>
} }

View File

@ -53,45 +53,40 @@ export function typecheck() {
* of types. For example: types.filter(filterGlobalTypes) * of types. For example: types.filter(filterGlobalTypes)
*/ */
function filterGlobalTypes(type: ts.Type): boolean { function filterGlobalTypes(type: ts.Type): boolean {
console.log('filterGlobalTypes', typeToString(type)) // console.log('fgt', typeToString(type))
if (type.aliasSymbol) {
// keep type aliases
return true
}
const symbol = type.getSymbol() const symbol = type.getSymbol()
if (!symbol) { if (!symbol) {
console.log(' no symbol') // console.log(' no symbol')
// e.g. string or number types have no symbol
return false return false
} }
if (symbol && !((symbol as any).parent)) { if (symbol && !((symbol as any).parent)) {
console.log(' no parent') // console.log(' no parent')
// e.g. Array symbol has no parent // e.g. Array symbol has no parent
return false return false
} }
if (type.isLiteral()) { if (type.isLiteral()) {
console.log(' is literal') // console.log(' is literal')
return false return false
} }
if (type.isUnionOrIntersection()) { if (type.isUnionOrIntersection()) {
console.log(' is union or intersection') // console.log(' is u or i')
// union type params should have already been extracted
return false return false
} }
if (isObjectType(type) && isTypeReference(type)) { if (isObjectType(type) && isTypeReference(type)) {
console.log(' is reference') // console.log(' is object type')
if (isObjectType(type.target) if (isObjectType(type.target) &&
&& type.target.objectFlags & ts.ObjectFlags.Tuple) { type.target.objectFlags & ts.ObjectFlags.Tuple) {
// console.log(' is tuple')
return false return false
} }
} }
// if (isObjectType(type) && type.objectFlags & ts.ObjectFlags.Tuple) {
// console.log(' is tuple')
// // tuple params should have already been extracted
// return false
// }
console.log(' ', // console.log(' keep!')
type.flags,
(type as any).objectFlags,
!!symbol,
symbol && !!(symbol as any).parent,
)
return true return true
} }
@ -99,6 +94,9 @@ export function typecheck() {
* Converts a generic type to the target of the type reference. * Converts a generic type to the target of the type reference.
*/ */
function mapGenericTypes(type: ts.Type): ts.Type { function mapGenericTypes(type: ts.Type): ts.Type {
if (type.aliasSymbol) {
return checker.getDeclaredTypeOfSymbol(type.aliasSymbol)
}
if (isObjectType(type) && isTypeReference(type)) { if (isObjectType(type) && isTypeReference(type)) {
return type.target return type.target
} }
@ -117,39 +115,32 @@ export function typecheck() {
* Recursively retrieves a list of all type parameters. * Recursively retrieves a list of all type parameters.
*/ */
function getAllTypeParameters(type: ts.Type): ts.Type[] { function getAllTypeParameters(type: ts.Type): ts.Type[] {
if (isObjectType(type) && isTypeReference(type)) { function collectTypeParams(
const types: ts.Type[] = [type] type2: ts.Type, params?: readonly ts.Type[],
): ts.Type[] {
if (type.typeArguments) { const types: ts.Type[] = [type2]
type.typeArguments.forEach(t => { if (params) {
const ta = getAllTypeParameters(t) params.forEach(t => {
types.push(...ta) const atp = getAllTypeParameters(t)
types.push(...atp)
}) })
} }
return types return types
} }
if (type.aliasSymbol) {
return collectTypeParams(type, type.aliasTypeArguments)
}
if (isObjectType(type) && isTypeReference(type)) {
return collectTypeParams(type, type.typeArguments)
}
if (type.isUnionOrIntersection()) { if (type.isUnionOrIntersection()) {
const unionOrIntersectionTypes = type.types return collectTypeParams(type, type.types)
// const types = [type, ...type.types]
const types: ts.Type[] = [type]
type.types.forEach(t => {
const tsp = getAllTypeParameters(t)
types.push(...tsp)
})
return types
} }
if (type.isClassOrInterface()) { if (type.isClassOrInterface()) {
if (type.typeParameters) { return collectTypeParams(type, type.typeParameters)
const types = [type, ...type.typeParameters]
type.typeParameters.forEach(t => {
const tsp = getAllTypeParameters(t)
types.push(...tsp)
})
return types
}
return [type]
} }
return [type] return [type]
@ -166,31 +157,23 @@ export function typecheck() {
) )
} }
/** function handleClassDeclaration(node: ts.ClassDeclaration) {
* Visit nodes finding exported classes if (!node.name) {
*/
function visit(node: ts.Node) {
// Only consider exported nodes
if (!isNodeExported(node)) {
return return
} }
if (ts.isClassDeclaration(node) && node.name) {
// This is a top level class, get its symbol // This is a top level class, get its symbol
const symbol = checker.getSymbolAtLocation(node.name) const symbol = checker.getSymbolAtLocation(node.name)
if (!symbol) {
return
}
const typeParameters: ts.TypeParameter[] = [] const typeParameters: ts.TypeParameter[] = []
const expandedTypeParameters: ts.Type[] = [] const expandedTypeParameters: ts.Type[] = []
const allRelevantTypes: ts.Type[] = [] const allRelevantTypes: ts.Type[] = []
if (symbol) {
// console.log('===')
// console.log('text', node.getText(node.getSourceFile()))
// console.log('class', symbol.getName())
const type = checker.getDeclaredTypeOfSymbol(symbol) const type = checker.getDeclaredTypeOfSymbol(symbol)
if (type.isClassOrInterface() && type.typeParameters) { if (type.isClassOrInterface() && type.typeParameters) {
type.typeParameters.forEach(tp => { type.typeParameters.forEach(tp => {
// console.log(' tp.symbol.name', tp.symbol.name)
const constraint = tp.getConstraint() const constraint = tp.getConstraint()
if (constraint) { if (constraint) {
expandedTypeParameters.push(...getAllTypeParameters(tp)) expandedTypeParameters.push(...getAllTypeParameters(tp))
@ -266,6 +249,18 @@ export function typecheck() {
classDefs.push(classDef) classDefs.push(classDef)
} }
/**
* Visit nodes finding exported classes
*/
function visit(node: ts.Node) {
// Only consider exported nodes
if (!isNodeExported(node)) {
return
}
if (ts.isClassDeclaration(node)) {
handleClassDeclaration(node)
} }
} }