function toTypeName()

in jsstub-generator/generate.ts [142:290]


function toTypeName(propertyType: ts.Node | undefined, moduleInfo: ModuleInfo, parentType: string | undefined = undefined, originalDefinition: string | undefined = undefined): TypeInfo {
    if (!propertyType) {
        return new TypeInfo('undefined', ['undefined']);
    }
    let result = propertyType.getText();
    let arrayDeep = 0;
    while (propertyType && propertyType.kind === ts.SyntaxKind.ArrayType) {
        arrayDeep++;
        propertyType = (<ts.ArrayTypeNode>propertyType).elementType;
    }
    if (arrayDeep > 0 && propertyType.kind === ts.SyntaxKind.TypeReference) {
        let realPropertyType = (<ts.TypeReferenceNode>propertyType).typeName;
        return new TypeInfo('new Array()',
            [(realPropertyType.kind === ts.SyntaxKind.QualifiedName
                ? realPropertyType.getText()
                : 'text' in realPropertyType
                    ? realPropertyType.text
                    : realPropertyType) + '[]'.repeat(arrayDeep)], result);
    }
    if (propertyType.kind === ts.SyntaxKind.AnyKeyword) {
        return new TypeInfo('new Object()', ['Object'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.StringKeyword) {
        return new TypeInfo('new String()', ['String'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.NumberKeyword) {
        return new TypeInfo('new Number()', ['Number'], originalDefinition);
   } else if (propertyType.kind === ts.SyntaxKind.UnknownKeyword) {
        return new TypeInfo('undefined', ['Object'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.BooleanKeyword) {
        return new TypeInfo('new Boolean()', ['Boolean'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.VoidKeyword) {
        return new TypeInfo('undefined', ['undefined'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.ObjectKeyword) {
        return new TypeInfo('new Object()', ['Object'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.UndefinedKeyword) {
        return new TypeInfo('undefined', ['undefined'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.LiteralType) {
        return new TypeInfo(result, [result], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.BigIntKeyword) {
        return new TypeInfo('BigInt(0)', ['BigInt'], originalDefinition);
    } else if (parentType && propertyType.kind === ts.SyntaxKind.ThisType) {
        return new TypeInfo('new ' + parentType + '()', [parentType], originalDefinition);
   } else if (propertyType.kind === ts.SyntaxKind.SymbolKeyword) {
        return new TypeInfo('new Symbol()', ['Symbol'], originalDefinition);
    } else if (result === 'unique symbol') {
        return new TypeInfo('new Symbol()', ['Symbol'], originalDefinition);
    } else if (propertyType.kind === ts.SyntaxKind.FunctionType) {
        return new TypeInfo('new Function()', ['Function'],  originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.ConstructorType) {
        return new TypeInfo('new Function()', ['Function'],  originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.TupleType) {
        return new TypeInfo('new Object()', ['Object'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.TypeLiteral) {
        // XXXX
        return new TypeInfo('new Object()', ['Object'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.FirstTypeNode) {
        return new TypeInfo('new Boolean()', ['Boolean'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.TypeQuery) {
        const entityName = (propertyType as ts.TypeQueryNode).exprName;
        let typeName = 'undefined';
        if(entityName.kind == ts.SyntaxKind.Identifier) {
            typeName = (entityName as ts.Identifier).text;
        } else if (entityName.kind == ts.SyntaxKind.QualifiedName) {
            typeName = (entityName as ts.QualifiedName).getText();
        }
        return new TypeInfo('new ' + typeName + '()', [typeName], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.TypeOperator) {
        return toTypeName((propertyType as ts.TypeOperatorNode).type, moduleInfo, parentType, originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.TypeReference) {
        let realPropertyType = (<ts.TypeReferenceNode>propertyType).typeName;
        if (moduleInfo.aliases.has(realPropertyType.getText())) {
            return toTypeName(
                            moduleInfo.aliases.get(realPropertyType.getText())!,
                            moduleInfo,
                            parentType,
                            originalDefinition ? originalDefinition : realPropertyType.getText()
                        );
        } else {
            const type = checker.getTypeAtLocation(propertyType);
            const symbol = type.symbol || type.aliasSymbol;
            let jsType = 'new Object()';
            let jsdocType = 'Object';
            if (symbol) {
                const decls = symbol.getDeclarations() as ts.Declaration[];
                let referencesInterface: boolean = false;
                decls.forEach(d => {
                    if (d.kind == ts.SyntaxKind.InterfaceDeclaration) {
                        referencesInterface = true;
                    }
                });
                if (referencesInterface) {
                    jsType = 'new ' + realPropertyType.getText() + '()';
                    jsdocType = realPropertyType.getText();
                    if ((!moduleInfo.classes.has(jsdocType)) && (moduleInfo.aliases.has(jsdocType))) {
                        return toTypeName(
                            moduleInfo.aliases.get(jsdocType)!,
                            moduleInfo,
                            parentType,
                            originalDefinition ? originalDefinition : realPropertyType.getText()
                        );
                    }
                }
            } else if (type.flags == ts.TypeFlags.Number) {
                jsType = 'new Number()';
                jsdocType = 'Number';
            }
            return new TypeInfo(jsType, [jsdocType], originalDefinition ? originalDefinition : realPropertyType.getText());
        }
    } else if (propertyType.kind === ts.SyntaxKind.IndexedAccessType && result === 'ArrayBufferTypes[keyof ArrayBufferTypes]') {
        return new TypeInfo('new ArrayBuffer()', ['ArrayBuffer'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind === ts.SyntaxKind.UnionType) {
        const types = (<ts.TypeNode[]> ((propertyType as any).types))
            .filter(t => t.kind !== ts.SyntaxKind.UndefinedKeyword && !(t.kind === ts.SyntaxKind.LiteralType && t.getText() === 'null') && t.kind !== ts.SyntaxKind.TypeQuery);
        let reducedTypeInfo: TypeInfo | undefined = undefined;
        if (types.length == 1) {
            reducedTypeInfo = toTypeName(types[0], moduleInfo, parentType, originalDefinition ? originalDefinition : result);
        }

        let jsdocType = (<ts.TypeNode[]> ((propertyType as any).types))
            .map(typeNode => toTypeName(typeNode, moduleInfo, parentType, originalDefinition ? originalDefinition : result))
            .map(ti => ti.jsdocType)
            .flat();

        if(reducedTypeInfo) {
            return new TypeInfo(reducedTypeInfo.jsType, jsdocType, originalDefinition ? originalDefinition : result);
        } else {
            return new TypeInfo('new Object()',  jsdocType, originalDefinition ? originalDefinition : result);
        }
    } else if (propertyType.kind === ts.SyntaxKind.IntersectionType) {
        const types = (<ts.TypeNode[]> ((propertyType as any).types))
            .filter(t => t.kind !== ts.SyntaxKind.UndefinedKeyword && !(t.kind === ts.SyntaxKind.LiteralType && t.getText() === 'null') && t.kind !== ts.SyntaxKind.TypeQuery);
        if (types.length == 1) {
            return toTypeName(types[0], moduleInfo, parentType, originalDefinition ? originalDefinition : result);
        }
        return new TypeInfo('new Object()', ['Object'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind == ts.SyntaxKind.ParenthesizedType) {
        return toTypeName((propertyType as ts.ParenthesizedTypeNode).type, moduleInfo, parentType, originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind == ts.SyntaxKind.ConditionalType && parentType === 'SubtleCrypto') {
        return toTypeName(moduleInfo.aliases.get('KeyFormat'), moduleInfo, parentType, originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind == ts.SyntaxKind.MappedType && (parentType === 'ResponseInit' || parentType === 'RequestInit' || parentType === 'PushSubscriptionJSON')) {
        return new TypeInfo('{}', ['Object.<String,String>'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind == ts.SyntaxKind.MappedType && (parentType === 'AudioWorkletNodeOptions')) {
        return new TypeInfo('{}', ['Object.<String,Number>'], originalDefinition ? originalDefinition : result);
    } else if (propertyType.kind == ts.SyntaxKind.MappedType && (parentType === 'Object')) {
        return new TypeInfo('new Object()', ['Object'], originalDefinition ? originalDefinition : result);
    } else {
        console.log('Unhandled type code: ' + ts.SyntaxKind[propertyType.kind] + ' / ' + result + ' / ' + parentType);
        return new TypeInfo('undefined', ['Object'], originalDefinition ? originalDefinition : result);
    }
}