Repository: microsoft/TypeScript
File: src/services/services.ts (TypeScript)

Code before:
}

/**
 * Gets all symbols for one property. Does not get symbols for every property.
 *
 * @internal
 */
export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker, contextualType: Type, unionSymbolOk: boolean): readonly Symbol[] {
    contextualType = contextualType.getNonNullableType();
    const name = getNameFromPropertyName(node.name);
    if (!name) return emptyArray;
    if (!contextualType.isUnion()) {
        const symbol = contextualType.getProperty(name);
        return symbol ? [symbol] : emptyArray;
    }

    const filteredTypes = isObjectLiteralExpression(node.parent) || isJsxAttributes(node.parent)
        ? filter(contextualType.types, t => !checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent))
        : contextualType.types;
    const discriminatedPropertySymbols = mapDefined(filteredTypes, t => t.getProperty(name));
    if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) {
        const symbol = contextualType.getProperty(name);
        if (symbol) return [symbol];
    }
    if (!filteredTypes.length && !discriminatedPropertySymbols.length) {
        // Bad discriminant -- do again without discriminating
        return mapDefined(contextualType.types, t => t.getProperty(name));
    }
    // by eliminating duplicates we might even end up with a single symbol
    // that helps with displaying better quick infos on properties of union types
    return deduplicate(discriminatedPropertySymbols, equateValues);
}

function isArgumentOfElementAccessExpression(node: Node) {
    return node &&
        node.parent &&
        node.parent.kind === SyntaxKind.ElementAccessExpression &&
        (node.parent as ElementAccessExpression).argumentExpression === node;
}

/**
 * Get the path of the default library files (lib.d.ts) as distributed with the typescript
 * node package.
 * The functionality is not supported if the ts module is consumed outside of a node module.
 */
export function getDefaultLibFilePath(options: CompilerOptions): string {
    if (sys) {
        return combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), getDefaultLibFileName(options));
    }

    throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. ");

Review comment (suggestion):
This just fine-tunes the algorithm for a common case. By discarding nullable (that can't provide anything useful here as they don't have properties anyway) the `!contextualType.isUnion()` "fast path" is taken here. This allows for better symbol result to be returned from here - despite those locations having errors. Without this the symbol of the anonymous object literal type (the one with error) is picked and that's less useful.

Code after:
    }
    return undefined;
}

/** @internal */
export type ObjectLiteralElementWithName = ObjectLiteralElement & { name: PropertyName; parent: ObjectLiteralExpression | JsxAttributes; };

function getSymbolAtLocationForQuickInfo(node: Node, checker: TypeChecker): Symbol | undefined {
    const object = getContainingObjectLiteralElement(node);
    if (object) {
        const contextualType = checker.getContextualType(object.parent);
        const properties = contextualType && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false);
        if (properties && properties.length === 1) {
            return first(properties);
        }
    }
    return checker.getSymbolAtLocation(node);
}

/**
 * Gets all symbols for one property. Does not get symbols for every property.
 *
 * @internal
 */
export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker, contextualType: Type, unionSymbolOk: boolean): readonly Symbol[] {
    contextualType = contextualType.getNonNullableType();
    const name = getNameFromPropertyName(node.name);
    if (!name) return emptyArray;
    if (!contextualType.isUnion()) {
        const symbol = contextualType.getProperty(name);
        return symbol ? [symbol] : emptyArray;
    }

    const filteredTypes = isObjectLiteralExpression(node.parent) || isJsxAttributes(node.parent)
        ? filter(contextualType.types, t => !checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent))
        : contextualType.types;
    const discriminatedPropertySymbols = mapDefined(filteredTypes, t => t.getProperty(name));
    if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) {
        const symbol = contextualType.getProperty(name);
        if (symbol) return [symbol];
    }
    if (!filteredTypes.length && !discriminatedPropertySymbols.length) {
        // Bad discriminant -- do again without discriminating
        return mapDefined(contextualType.types, t => t.getProperty(name));
    }
    // by eliminating duplicates we might even end up with a single symbol
    // that helps with displaying better quick infos on properties of union types
    return deduplicate(discriminatedPropertySymbols, equateValues);
}

function isArgumentOfElementAccessExpression(node: Node) {