Compare commits

...

9 commits

Author SHA1 Message Date
Andy Hanson b425453767 wip 2017-05-31 08:22:26 -07:00
Andy Hanson ee57dc894b wip 2017-05-31 08:18:50 -07:00
Andy Hanson 619a5152df wip 2017-05-31 07:48:23 -07:00
Andy Hanson 51feae52b4 wip 2017-05-31 07:48:05 -07:00
Andy Hanson 62e079520d wip: tests pass 2017-05-31 07:48:05 -07:00
Andy Hanson 2648af160d wip 2017-05-31 07:48:05 -07:00
Andy Hanson 8a8ceebbac wip 2017-05-31 07:48:05 -07:00
Andy Hanson 5335dfa31a wip 2017-05-31 07:48:04 -07:00
Andy Hanson 5a816980e2 wip 2017-05-31 07:47:50 -07:00
28 changed files with 936 additions and 79 deletions

View file

@ -9278,6 +9278,10 @@ namespace ts {
let result = Ternary.True;
const properties = getPropertiesOfObjectType(target);
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
let _privatesCompatible: boolean | undefined;
const privatesCompatible = () => _privatesCompatible !== undefined ? _privatesCompatible : _privatesCompatible = classPrivatesAreCompatible(source, target);
for (const targetProp of properties) {
const sourceProp = getPropertyOfType(source, targetProp.name);
@ -9293,7 +9297,7 @@ namespace ts {
else if (!(targetProp.flags & SymbolFlags.Prototype)) {
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
if ((sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) && !privatesCompatible()) {
if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate) {
if (reportErrors) {
reportError(Diagnostics.Property_0_has_conflicting_declarations_and_is_inaccessible_in_type_1, symbolToString(sourceProp), typeToString(source));
@ -9314,7 +9318,7 @@ namespace ts {
return Ternary.False;
}
}
else if (targetPropFlags & ModifierFlags.Protected) {
else if (targetPropFlags & ModifierFlags.Protected && !privatesCompatible()) {
if (!isValidOverrideOf(sourceProp, targetProp)) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp),
@ -9323,7 +9327,7 @@ namespace ts {
return Ternary.False;
}
}
else if (sourcePropFlags & ModifierFlags.Protected) {
else if (sourcePropFlags & ModifierFlags.Protected && !privatesCompatible()) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2,
symbolToString(targetProp), typeToString(source), typeToString(target));
@ -24636,4 +24640,30 @@ namespace ts {
}
}
function classPrivatesAreCompatible(a: Type, b: Type): boolean {
const classA = a.symbol.valueDeclaration;
const classB = b.symbol.valueDeclaration;
return classA && classB && isClassLike(classA) && isClassLike(classB) && nodesHavePrivateCompatibleOrigins(classA, classB);
}
function nodesHavePrivateCompatibleOrigins<T extends ClassLikeDeclaration | ModuleDeclaration>(a: T, b: T): boolean {
return (a.name && a.name.text) === (b.name && b.name.text)
&& getModifierFlags(a) === getModifierFlags(b)
&& parentsHavePrivateCompatibleOrigins(a.parent, b.parent);
}
function parentsHavePrivateCompatibleOrigins(parentA: Node, parentB: Node): boolean {
if (parentA.kind !== parentB.kind) return false;
switch (parentA.kind) {
case SyntaxKind.ExportAssignment:
return parentsHavePrivateCompatibleOrigins(parentA.parent, parentB.parent);
case SyntaxKind.ModuleBlock:
return nodesHavePrivateCompatibleOrigins((parentA as ModuleBlock).parent, (parentB as ModuleBlock).parent);
case SyntaxKind.SourceFile:
return (parentA as SourceFile).packageName !== undefined && (parentA as SourceFile).packageName === (parentB as SourceFile).packageName;
default:
return false;
}
}
}

View file

@ -19,13 +19,33 @@ namespace ts {
push(value: T): void;
}
//name
interface ResolvedMini {
path: string;
extension: Extension;
}
function maybeWithPackageName(packageName: string | undefined, r: ResolvedMini | undefined): Resolved | undefined {
return r && { ...r, packageName: packageName && normalizePackageName(packageName) };
}
function normalizePackageName(packageName: string): string {
let components = getNormalizedPathComponents(packageName, "");
if (components[0] === "") {
components = components.slice(1);
}
if (components[0] === "@types") {
components = components.slice(1);
}
return getNormalizedPathFromPathComponents(components);
}
/**
* Result of trying to resolve a module.
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
*/
interface Resolved {
path: string;
extension: Extension;
interface Resolved extends ResolvedMini {
packageName: string;
}
/**
@ -39,7 +59,7 @@ namespace ts {
}
/** Used with `Extensions.DtsOnly` to extract the path from TypeScript results. */
function resolvedTypeScriptOnly(resolved: Resolved | undefined): string | undefined {
function resolvedTypeScriptOnly(resolved: ResolvedMini | undefined): string | undefined {
if (!resolved) {
return undefined;
}
@ -48,8 +68,9 @@ namespace ts {
}
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
Debug.assert(!resolved || resolved.path !== undefined); //kill
return {
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, packageName: resolved.packageName, isExternalLibraryImport },
failedLookupLocations
};
}
@ -474,7 +495,7 @@ namespace ts {
* 'typings' entry or file 'index' with some supported extension
* - Classic loader will only try to interpret '/a/b/c' as file.
*/
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState) => ResolvedMini | undefined;
/**
* Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
@ -540,15 +561,15 @@ namespace ts {
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (moduleHasNonRelativeName(moduleName)) {
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
return maybeWithPackageName(moduleName, tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state)); //TODO: Test with baseUrl settings...
}
else {
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
return maybeWithPackageName(undefined, tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state));
}
}
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
failedLookupLocations: Push<string>, state: ModuleResolutionState): ResolvedMini | undefined {
if (!state.compilerOptions.rootDirs) {
return undefined;
@ -624,7 +645,7 @@ namespace ts {
return undefined;
}
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, failedLookupLocations: Push<string>, state: ModuleResolutionState): ResolvedMini | undefined {
if (!state.compilerOptions.baseUrl) {
return undefined;
}
@ -658,7 +679,8 @@ namespace ts {
if (extension !== undefined) {
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
if (path !== undefined) {
return { path, extension };
const packageName = ts.removeExtension(candidate, extensionToString(extension)); //test
return { path, packageName, extension };
}
}
@ -721,11 +743,16 @@ namespace ts {
}
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
return resolved && { value: resolved.value && { resolved: { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }, isExternalLibraryImport: true } };
return resolved && {
value: resolved.value && {
resolved: maybeWithPackageName(moduleName, { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }),
isExternalLibraryImport: true
}
};
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
const resolved = maybeWithPackageName(undefined, nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true));
return resolved && toSearchResult({ resolved, isExternalLibraryImport: false });
}
}
@ -743,7 +770,7 @@ namespace ts {
return real;
}
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): ResolvedMini | undefined {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
}
@ -784,7 +811,7 @@ namespace ts {
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
*/
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): ResolvedMini | undefined {
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
if (resolvedByAddingExtension) {
@ -804,7 +831,7 @@ namespace ts {
}
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): ResolvedMini | undefined {
if (!onlyRecordFailures) {
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
const directory = getDirectoryPath(candidate);
@ -815,20 +842,33 @@ namespace ts {
switch (extensions) {
case Extensions.DtsOnly:
return tryExtension(".d.ts", Extension.Dts);
return tryExtension(Extension.Dts);
case Extensions.TypeScript:
return tryExtension(".ts", Extension.Ts) || tryExtension(".tsx", Extension.Tsx) || tryExtension(".d.ts", Extension.Dts);
return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || tryExtension(Extension.Dts);
case Extensions.JavaScript:
return tryExtension(".js", Extension.Js) || tryExtension(".jsx", Extension.Jsx);
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
}
function tryExtension(ext: string, extension: Extension): Resolved | undefined {
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
function tryExtension(extension: Extension): ResolvedMini | undefined {
const path = tryFile(candidate + extensionToString(extension), failedLookupLocations, onlyRecordFailures, state);
return path && { path, extension };
}
}
//mv
function extensionToString(ext: Extension): string {
switch (ext) {
case Extension.Dts: return ".d.ts";
case Extension.Ts: return ".ts";
case Extension.Tsx: return ".tsx";
case Extension.Dts: return ".d.ts";
case Extension.Js: return ".js";
case Extension.Jsx: return ".jsx";
}
}
/** Return the file if it exists. */
//This returns its input. Silly.
function tryFile(fileName: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
if (!onlyRecordFailures) {
if (state.host.fileExists(fileName)) {
@ -847,7 +887,7 @@ namespace ts {
return undefined;
}
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): ResolvedMini | undefined {
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
if (considerPackageJson) {
@ -870,7 +910,7 @@ namespace ts {
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
}
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): ResolvedMini | undefined { //this should of course be global...
if (state.traceEnabled) {
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
@ -899,7 +939,7 @@ namespace ts {
}
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
function resolvedIfExtensionMatches(extensions: Extensions, path: string): ResolvedMini | undefined {
const extension = tryGetExtensionFromPath(path);
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
}
@ -920,22 +960,22 @@ namespace ts {
return combinePaths(directory, "package.json");
}
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): ResolvedMini | undefined {
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
return loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
}
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult<Resolved> {
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult<ResolvedMini> {
return loadModuleFromNodeModulesWorker(extensions, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ false, cache);
}
function loadModuleFromNodeModulesAtTypes(moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): SearchResult<Resolved> {
function loadModuleFromNodeModulesAtTypes(moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): SearchResult<ResolvedMini> {
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
return loadModuleFromNodeModulesWorker(Extensions.DtsOnly, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ true, /*cache*/ undefined);
}
function loadModuleFromNodeModulesWorker(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean, cache: NonRelativeModuleNameResolutionCache): SearchResult<Resolved> {
function loadModuleFromNodeModulesWorker(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean, cache: NonRelativeModuleNameResolutionCache): SearchResult<ResolvedMini> {
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
if (getBaseFileName(ancestorDirectory) !== "node_modules") {
@ -949,7 +989,7 @@ namespace ts {
}
/** Load a module from a single node_modules directory, but not from any ancestors' node_modules directories. */
function loadModuleFromNodeModulesOneLevel(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly = false): Resolved | undefined {
function loadModuleFromNodeModulesOneLevel(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly = false): ResolvedMini | undefined {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
if (!nodeModulesFolderExists && state.traceEnabled) {
@ -1008,7 +1048,7 @@ namespace ts {
if (traceEnabled) {
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
}
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, packageName: result.resolvedModule.packageName, extension: result.resolvedModule.extension } };
}
}
@ -1036,19 +1076,20 @@ namespace ts {
return resolutionFromCache;
}
const searchName = normalizePath(combinePaths(directory, moduleName));
return toSearchResult(loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(maybeWithPackageName(moduleName, loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state)));
});
if (resolved) {
return resolved;
}
if (extensions === Extensions.TypeScript) {
// If we didn't find the file normally, look it up in @types.
return loadModuleFromNodeModulesAtTypes(moduleName, containingDirectory, failedLookupLocations, state);
const x = loadModuleFromNodeModulesAtTypes(moduleName, containingDirectory, failedLookupLocations, state);
return x && { value: maybeWithPackageName(moduleName, x.value) }
}
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
return toSearchResult(loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(maybeWithPackageName(undefined, loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state)));
}
}
}
@ -1065,7 +1106,7 @@ namespace ts {
}
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const failedLookupLocations: string[] = [];
const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state);
const resolved = maybeWithPackageName(moduleName, loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state));
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
}

View file

@ -756,6 +756,8 @@ namespace ts {
sourceFile.languageVariant = getLanguageVariant(scriptKind);
sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, ".d.ts");
sourceFile.scriptKind = scriptKind;
// This will be set in 'program.ts' if the file is imported from an external package.
sourceFile.packageName = undefined;
return sourceFile;
}

View file

@ -449,6 +449,7 @@ namespace ts {
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
// Host may not have set packageName, but it's OK to leave it as undefined.
return resolved as ResolvedModuleFull;
}
const withExtension = clone(resolved) as ResolvedModuleFull;
@ -767,8 +768,9 @@ namespace ts {
for (const oldSourceFile of oldProgram.getSourceFiles()) {
const newSourceFile = host.getSourceFileByPath
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
: host.getSourceFile(oldSourceFile.fileName, options.target);
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target, undefined)
: host.getSourceFile(oldSourceFile.fileName, options.target, undefined);
//may need to set newSourceFile.packageName === oldSourceFile.packageName ?
if (!newSourceFile) {
return oldProgram.structureIsReused = StructureIsReused.Not;
@ -1501,7 +1503,8 @@ namespace ts {
/** This has side effects through `findSourceFile`. */
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
getSourceFileFromReferenceWorker(fileName,
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
//OK for packageName to be undefined?
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), /*packageName*/ undefined, isDefaultLib, refFile, refPos, refEnd),
(diagnostic, ...args) => {
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
@ -1521,18 +1524,22 @@ namespace ts {
}
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
function findSourceFile(fileName: string, path: Path, packageName: string | undefined, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
if (!file) return undefined;
setPackageName(file, packageName);
// try to check if we've already seen this file but with a different casing in path
// NOTE: this only makes sense for case-insensitive file systems
if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== getNormalizedAbsolutePath(fileName, currentDirectory)) {
if (options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== getNormalizedAbsolutePath(fileName, currentDirectory)) {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}
// If the file was previously found via a node_modules search, but is now being processed as a root file,
// then everything it sucks in may also be marked incorrectly, and needs to be checked again.
if (file && sourceFilesFoundSearchingNodeModules.get(file.path) && currentNodeModulesDepth === 0) {
if (sourceFilesFoundSearchingNodeModules.get(file.path) && currentNodeModulesDepth === 0) {
sourceFilesFoundSearchingNodeModules.set(file.path, false);
if (!options.noResolve) {
processReferencedFiles(file, isDefaultLib);
@ -1543,7 +1550,7 @@ namespace ts {
processImportedModules(file);
}
// See if we need to reprocess the imports due to prior skipped imports
else if (file && modulesWithElidedImports.get(file.path)) {
else if (modulesWithElidedImports.get(file.path)) {
if (currentNodeModulesDepth < maxNodeModuleJsDepth) {
modulesWithElidedImports.set(file.path, false);
processImportedModules(file);
@ -1565,42 +1572,56 @@ namespace ts {
});
filesByName.set(path, file);
if (file) {
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
file.path = path;
if (!file) return undefined;
if (host.useCaseSensitiveFileNames()) {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(path);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
}
else {
filesByNameIgnoreCase.set(path, file);
}
}
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
setPackageName(file, packageName);
file.path = path;
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
if (!options.noResolve) {
processReferencedFiles(file, isDefaultLib);
processTypeReferenceDirectives(file);
}
// always process imported modules to record module name resolutions
processImportedModules(file);
if (isDefaultLib) {
files.unshift(file);
if (host.useCaseSensitiveFileNames()) {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(path);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
}
else {
files.push(file);
filesByNameIgnoreCase.set(path, file);
}
}
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
if (!options.noResolve) {
processReferencedFiles(file, isDefaultLib);
processTypeReferenceDirectives(file);
}
// always process imported modules to record module name resolutions
processImportedModules(file);
if (isDefaultLib) {
files.unshift(file);
}
else {
files.push(file);
}
return file;
}
function setPackageName(file: SourceFile, packageName: string | undefined): void {
if (packageName === undefined) {
return;
}
else if (file.packageName === undefined) {
file.packageName = packageName;
}
else {
Debug.assert(file.packageName === packageName, "Same source file loaded from two different packages", () =>
`Packages are ${file.packageName} and ${packageName}`);
}
}
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
@ -1634,6 +1655,7 @@ namespace ts {
let saveResolution = true;
if (resolvedTypeReferenceDirective) {
if (resolvedTypeReferenceDirective.primary) {
//pass along resolvedTypeReferenceDirective.packageName?
// resolved from the primary path
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, refFile, refPos, refEnd);
}
@ -1725,7 +1747,7 @@ namespace ts {
else if (shouldAddFile) {
const path = toPath(resolvedFileName, currentDirectory, getCanonicalFileName);
const pos = skipTrivia(file.text, file.imports[i].pos);
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
findSourceFile(resolvedFileName, path, resolution.packageName, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
}
if (isFromNodeModulesSearch) {

View file

@ -1976,7 +1976,7 @@ namespace ts {
export interface ExportAssignment extends DeclarationStatement {
kind: SyntaxKind.ExportAssignment;
parent?: SourceFile;
parent?: SourceFile | ModuleBlock;
isExportEquals?: boolean;
expression: Expression;
}
@ -2280,10 +2280,12 @@ namespace ts {
fileName: string;
/* @internal */ path: Path;
/** This will be set if the source file is resolved from an external library import. */
/* @internal */ packageName: string | undefined;
text: string;
amdDependencies: AmdDependency[];
moduleName: string;
moduleName: string; // This is set by an `/// <amd-module name="foo" />` directive.
referencedFiles: FileReference[];
typeReferenceDirectives: FileReference[];
languageVariant: LanguageVariant;
@ -3849,6 +3851,11 @@ namespace ts {
* This is optional for backwards-compatibility, but will be added if not provided.
*/
extension: Extension;
/**
* Name of the external library that the resolution came from.
* For `node_modules/@types/foo/bar.d.ts`, the packageName should be `foo/bar`.
*/
packageName?: string;
}
export enum Extension {
@ -3866,6 +3873,7 @@ namespace ts {
failedLookupLocations: string[];
}
//packageName here?
export interface ResolvedTypeReferenceDirective {
// True if the type declaration file was found in a primary lookup location
primary: boolean;

View file

@ -19,8 +19,8 @@ namespace ts {
assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations);
}
export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModuleFull {
return { resolvedFileName, extension: extensionFromPath(resolvedFileName), isExternalLibraryImport };
export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false, packageName?: string): ResolvedModuleFull {
return { resolvedFileName, extension: extensionFromPath(resolvedFileName), packageName, isExternalLibraryImport };
}
interface File {

View file

@ -12,7 +12,7 @@ namespace ts {
};
}
describe("printFile", () => {
it("printFile", () => {
const printsCorrectly = makePrintsCorrectly("printsFileCorrectly");
const sourceFile = createSourceFile("source.ts", `
interface A<T> {
@ -57,7 +57,7 @@ namespace ts {
printsCorrectly("templateLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ScriptTarget.ES2017)));
});
describe("printBundle", () => {
it("printBundle", () => {
const printsCorrectly = makePrintsCorrectly("printsBundleCorrectly");
const bundle = createBundle([
createSourceFile("a.ts", `
@ -77,7 +77,7 @@ namespace ts {
printsCorrectly("removeComments", { removeComments: true }, printer => printer.printBundle(bundle));
});
describe("printNode", () => {
it("printNode", () => {
const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
const sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015);
// tslint:disable boolean-trivia

View file

@ -482,6 +482,7 @@ namespace ts {
public kind: SyntaxKind.SourceFile;
public _declarationBrand: any;
public fileName: string;
/* @internal */ public packageName: string | undefined;
public path: Path;
public text: string;
public scriptSnapshot: IScriptSnapshot;

View file

@ -327,7 +327,7 @@ namespace ts {
const resolutionsInFile = <MapLike<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
return map(moduleNames, name => {
const result = getProperty(resolutionsInFile, name);
return result ? { resolvedFileName: result, extension: extensionFromPath(result), isExternalLibraryImport: false } : undefined;
return result ? { resolvedFileName: result, extension: extensionFromPath(result), packageName: undefined, isExternalLibraryImport: false } : undefined;
});
};
}

View file

@ -0,0 +1,19 @@
/a.ts(6,23): error TS6137: Cannot import type declaration files. Consider importing 'foo/' instead of '@types/foo/'.
==== /a.ts (1 errors) ====
// These imports must all resolve with the same packageName of "foo",
// or else it will trigger an assertion in `setPackageName` in `program.ts`
import * as foo from "foo";
import * as foo2 from "foo/";
import * as foo3 from "@types/foo/";
~~~~~~~~~~~~~
!!! error TS6137: Cannot import type declaration files. Consider importing 'foo/' instead of '@types/foo/'.
import * as foo4 from "@types\\foo\\";
// Relative imports do not have any packageName, so ignored.
import * as foo5 from "./node_modules/@types/foo";
==== /node_modules/@types/foo/index.d.ts (0 errors) ====
export const x: number;

View file

@ -0,0 +1,22 @@
//// [tests/cases/compiler/moduleResolution_packageNameConsistent.ts] ////
//// [a.ts]
// These imports must all resolve with the same packageName of "foo",
// or else it will trigger an assertion in `setPackageName` in `program.ts`
import * as foo from "foo";
import * as foo2 from "foo/";
import * as foo3 from "@types/foo/";
import * as foo4 from "@types\\foo\\";
// Relative imports do not have any packageName, so ignored.
import * as foo5 from "./node_modules/@types/foo";
//// [index.d.ts]
export const x: number;
//// [a.js]
"use strict";
// These imports must all resolve with the same packageName of "foo",
// or else it will trigger an assertion in `setPackageName` in `program.ts`
exports.__esModule = true;

View file

@ -0,0 +1,62 @@
/src/a.ts(6,3): error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
Types of property 'x' are incompatible.
Type 'string' is not assignable to type 'number'.
/src/a.ts(7,3): error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
Types have separate declarations of a private property 'x'.
==== /node_modules/a/index.d.ts (0 errors) ====
import X from "x";
export function a(x: X): void;
==== /node_modules/a/node_modules/x/index.d.ts (0 errors) ====
export default class X {
private x: number;
}
==== /node_modules/b/index.d.ts (0 errors) ====
import X from "x";
export const b: X;
==== /node_modules/b/node_modules/x/index.d.ts (0 errors) ====
export default class X {
private x: number;
}
==== /node_modules/c/index.d.ts (0 errors) ====
import X from "x";
export const c: X;
==== /node_modules/c/node_modules/x/index.d.ts (0 errors) ====
// Mismatch -- different type
export default class X {
private x: string;
}
==== /node_modules/d/index.d.ts (0 errors) ====
import { X } from "x";
export const d: X;
==== /node_modules/d/node_modules/x/index.d.ts (0 errors) ====
// Mismatch -- is a named export, not a default export
export class X {
private x: number;
}
==== /src/a.ts (2 errors) ====
import { a } from "a";
import { b } from "b";
import { c } from "c";
import { d } from "d";
a(b); // Works
a(c); // Error
~
!!! error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
!!! error TS2345: Types of property 'x' are incompatible.
!!! error TS2345: Type 'string' is not assignable to type 'number'.
a(d); // Error
~
!!! error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
!!! error TS2345: Types have separate declarations of a private property 'x'.

View file

@ -0,0 +1,61 @@
//// [tests/cases/compiler/nominalTypeMatchingDuplicateDeclarations0.ts] ////
//// [index.d.ts]
import X from "x";
export function a(x: X): void;
//// [index.d.ts]
export default class X {
private x: number;
}
//// [index.d.ts]
import X from "x";
export const b: X;
//// [index.d.ts]
export default class X {
private x: number;
}
//// [index.d.ts]
import X from "x";
export const c: X;
//// [index.d.ts]
// Mismatch -- different type
export default class X {
private x: string;
}
//// [index.d.ts]
import { X } from "x";
export const d: X;
//// [index.d.ts]
// Mismatch -- is a named export, not a default export
export class X {
private x: number;
}
//// [a.ts]
import { a } from "a";
import { b } from "b";
import { c } from "c";
import { d } from "d";
a(b); // Works
a(c); // Error
a(d); // Error
//// [a.js]
"use strict";
exports.__esModule = true;
var a_1 = require("a");
var b_1 = require("b");
var c_1 = require("c");
var d_1 = require("d");
a_1.a(b_1.b); // Works
a_1.a(c_1.c); // Error
a_1.a(d_1.d); // Error

View file

@ -0,0 +1,64 @@
/src/a.ts(9,7): error TS2345: Argument of type 'G.N.X' is not assignable to parameter of type 'G.M.X'.
Types have separate declarations of a private property 'x'.
/src/a.ts(10,7): error TS2345: Argument of type 'G.N.X' is not assignable to parameter of type 'G.M.X'.
Types have separate declarations of a private property 'x'.
==== /node_modules/a/index.d.ts (0 errors) ====
import { G } from "x";
export function useMX(x: G.M.X): void;
export function useNX(x: G.N.X): void;
export const an: G.N.X;
==== /node_modules/a/node_modules/x/index.d.ts (0 errors) ====
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
==== /node_modules/b/index.d.ts (0 errors) ====
import { G } from "x";
export const bm: G.M.X;
export const bn: G.N.X;
==== /node_modules/b/node_modules/x/index.d.ts (0 errors) ====
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
==== /src/a.ts (2 errors) ====
import { an, useMX, useNX } from "a";
import { bm, bn } from "b";
// Works:
useMX(bm);
useNX(bn);
// Error:
useMX(an);
~~
!!! error TS2345: Argument of type 'G.N.X' is not assignable to parameter of type 'G.M.X'.
!!! error TS2345: Types have separate declarations of a private property 'x'.
useMX(bn);
~~
!!! error TS2345: Argument of type 'G.N.X' is not assignable to parameter of type 'G.M.X'.
!!! error TS2345: Types have separate declarations of a private property 'x'.

View file

@ -0,0 +1,66 @@
//// [tests/cases/compiler/nominalTypeMatchingDuplicateDeclarations1.ts] ////
//// [index.d.ts]
import { G } from "x";
export function useMX(x: G.M.X): void;
export function useNX(x: G.N.X): void;
export const an: G.N.X;
//// [index.d.ts]
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
//// [index.d.ts]
import { G } from "x";
export const bm: G.M.X;
export const bn: G.N.X;
//// [index.d.ts]
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
//// [a.ts]
import { an, useMX, useNX } from "a";
import { bm, bn } from "b";
// Works:
useMX(bm);
useNX(bn);
// Error:
useMX(an);
useMX(bn);
//// [a.js]
"use strict";
exports.__esModule = true;
var a_1 = require("a");
var b_1 = require("b");
// Works:
a_1.useMX(b_1.bm);
a_1.useNX(b_1.bn);
// Error:
a_1.useMX(a_1.an);
a_1.useMX(b_1.bn);

View file

@ -0,0 +1,46 @@
/src/a.ts(5,3): error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
Property 'x' is missing in type 'X'.
==== /node_modules/a/index.d.ts (0 errors) ====
import X from "x";
export function a(x: X): void;
==== /node_modules/a/node_modules/x/index.d.ts (0 errors) ====
export default class X {
protected m(): void;
private x: number;
}
==== /node_modules/b/index.d.ts (0 errors) ====
import X from "x";
export const b: X;
==== /node_modules/b/node_modules/x/index.d.ts (0 errors) ====
export default class X {
protected m(): void;
private x: number;
// OK to provide more members
private y: number;
}
==== /node_modules/c/index.d.ts (0 errors) ====
import X from "x";
export const c: X;
==== /node_modules/c/node_modules/x/index.d.ts (0 errors) ====
export default class X {
protected m(): void;
// Not OK to be missing a member
}
==== /src/a.ts (1 errors) ====
import { a } from "a";
import { b } from "b";
import { c } from "c";
a(b);
a(c); // Error
~
!!! error TS2345: Argument of type 'X' is not assignable to parameter of type 'X'.
!!! error TS2345: Property 'x' is missing in type 'X'.

View file

@ -0,0 +1,50 @@
//// [tests/cases/compiler/nominalTypeMatchingDuplicateDeclarations2.ts] ////
//// [index.d.ts]
import X from "x";
export function a(x: X): void;
//// [index.d.ts]
export default class X {
protected m(): void;
private x: number;
}
//// [index.d.ts]
import X from "x";
export const b: X;
//// [index.d.ts]
export default class X {
protected m(): void;
private x: number;
// OK to provide more members
private y: number;
}
//// [index.d.ts]
import X from "x";
export const c: X;
//// [index.d.ts]
export default class X {
protected m(): void;
// Not OK to be missing a member
}
//// [a.ts]
import { a } from "a";
import { b } from "b";
import { c } from "c";
a(b);
a(c); // Error
//// [a.js]
"use strict";
exports.__esModule = true;
var a_1 = require("a");
var b_1 = require("b");
var c_1 = require("c");
a_1.a(b_1.b);
a_1.a(c_1.c); // Error

View file

@ -0,0 +1,34 @@
//// [tests/cases/compiler/nominalTypeMatchingDuplicateDeclarations3.ts] ////
//// [index.d.ts]
import X = require("x");
export { X as A };
//// [index.d.ts]
export = class {
private m(): void;
}
//// [index.d.ts]
import X = require("x");
export { X as B };
//// [index.d.ts]
export = class {
private m(): void;
}
//// [a.ts]
import { A } from "a";
import { B } from "b";
let a = new A();
a = new B();
//// [a.js]
"use strict";
exports.__esModule = true;
var a_1 = require("a");
var b_1 = require("b");
var a = new a_1.A();
a = new b_1.B();

View file

@ -0,0 +1,43 @@
=== /node_modules/a/index.d.ts ===
import X = require("x");
>X : Symbol(X, Decl(index.d.ts, 0, 0))
export { X as A };
>X : Symbol(A, Decl(index.d.ts, 1, 8))
>A : Symbol(A, Decl(index.d.ts, 1, 8))
=== /node_modules/a/node_modules/x/index.d.ts ===
export = class {
private m(): void;
>m : Symbol((Anonymous class).m, Decl(index.d.ts, 0, 16))
}
=== /node_modules/b/index.d.ts ===
import X = require("x");
>X : Symbol(X, Decl(index.d.ts, 0, 0))
export { X as B };
>X : Symbol(B, Decl(index.d.ts, 1, 8))
>B : Symbol(B, Decl(index.d.ts, 1, 8))
=== /node_modules/b/node_modules/x/index.d.ts ===
export = class {
private m(): void;
>m : Symbol((Anonymous class).m, Decl(index.d.ts, 0, 16))
}
=== /src/a.ts ===
import { A } from "a";
>A : Symbol(A, Decl(a.ts, 0, 8))
import { B } from "b";
>B : Symbol(B, Decl(a.ts, 1, 8))
let a = new A();
>a : Symbol(a, Decl(a.ts, 2, 3))
>A : Symbol(A, Decl(a.ts, 0, 8))
a = new B();
>a : Symbol(a, Decl(a.ts, 2, 3))
>B : Symbol(B, Decl(a.ts, 1, 8))

View file

@ -0,0 +1,50 @@
=== /node_modules/a/index.d.ts ===
import X = require("x");
>X : typeof (Anonymous class)
export { X as A };
>X : typeof (Anonymous class)
>A : typeof (Anonymous class)
=== /node_modules/a/node_modules/x/index.d.ts ===
export = class {
>class { private m(): void;} : typeof (Anonymous class)
private m(): void;
>m : () => void
}
=== /node_modules/b/index.d.ts ===
import X = require("x");
>X : typeof (Anonymous class)
export { X as B };
>X : typeof (Anonymous class)
>B : typeof (Anonymous class)
=== /node_modules/b/node_modules/x/index.d.ts ===
export = class {
>class { private m(): void;} : typeof (Anonymous class)
private m(): void;
>m : () => void
}
=== /src/a.ts ===
import { A } from "a";
>A : typeof (Anonymous class)
import { B } from "b";
>B : typeof (Anonymous class)
let a = new A();
>a : (Anonymous class)
>new A() : (Anonymous class)
>A : typeof (Anonymous class)
a = new B();
>a = new B() : (Anonymous class)
>a : (Anonymous class)
>new B() : (Anonymous class)
>B : typeof (Anonymous class)

View file

@ -0,0 +1,23 @@
/src/a.ts(4,1): error TS90010: Type 'C' is not assignable to type 'C'. Two different types with this name exist, but they are unrelated.
Types have separate declarations of a private property 'm'.
==== /node_modules/a/c0.d.ts (0 errors) ====
export class C {
private m(): void;
}
==== /node_modules/a/c1.d.ts (0 errors) ====
export class C {
private m(): void;
}
==== /src/a.ts (1 errors) ====
import { C as C0 } from "a/c0";
import { C as C1 } from "a/c1";
let c = new C0();
c = new C1();
~
!!! error TS90010: Type 'C' is not assignable to type 'C'. Two different types with this name exist, but they are unrelated.
!!! error TS90010: Types have separate declarations of a private property 'm'.

View file

@ -0,0 +1,26 @@
//// [tests/cases/compiler/nominalTypeMatchingDuplicateDeclarations4.ts] ////
//// [c0.d.ts]
export class C {
private m(): void;
}
//// [c1.d.ts]
export class C {
private m(): void;
}
//// [a.ts]
import { C as C0 } from "a/c0";
import { C as C1 } from "a/c1";
let c = new C0();
c = new C1();
//// [a.js]
"use strict";
exports.__esModule = true;
var c0_1 = require("a/c0");
var c1_1 = require("a/c1");
var c = new c0_1.C();
c = new c1_1.C();

View file

@ -0,0 +1,13 @@
// These imports must all resolve with the same packageName of "foo",
// or else it will trigger an assertion in `setPackageName` in `program.ts`
// @Filename: /a.ts
import * as foo from "foo";
import * as foo2 from "foo/";
import * as foo3 from "@types/foo/";
import * as foo4 from "@types\\foo\\";
// Relative imports do not have any packageName, so ignored.
import * as foo5 from "./node_modules/@types/foo";
// @Filename: /node_modules/@types/foo/index.d.ts
export const x: number;

View file

@ -0,0 +1,47 @@
// @Filename: /node_modules/a/index.d.ts
import X from "x";
export function a(x: X): void;
// @Filename: /node_modules/a/node_modules/x/index.d.ts
export default class X {
private x: number;
}
// @Filename: /node_modules/b/index.d.ts
import X from "x";
export const b: X;
// @Filename: /node_modules/b/node_modules/x/index.d.ts
export default class X {
private x: number;
}
// @Filename: /node_modules/c/index.d.ts
import X from "x";
export const c: X;
// @Filename: /node_modules/c/node_modules/x/index.d.ts
// Mismatch -- different type
export default class X {
private x: string;
}
// @Filename: /node_modules/d/index.d.ts
import { X } from "x";
export const d: X;
// @Filename: /node_modules/d/node_modules/x/index.d.ts
// Mismatch -- is a named export, not a default export
export class X {
private x: number;
}
// @Filename: /src/a.ts
import { a } from "a";
import { b } from "b";
import { c } from "c";
import { d } from "d";
a(b); // Works
a(c); // Error
a(d); // Error

View file

@ -0,0 +1,51 @@
// @Filename: /node_modules/a/index.d.ts
import { G } from "x";
export function useMX(x: G.M.X): void;
export function useNX(x: G.N.X): void;
export const an: G.N.X;
// @Filename: /node_modules/a/node_modules/x/index.d.ts
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
// @Filename: /node_modules/b/index.d.ts
import { G } from "x";
export const bm: G.M.X;
export const bn: G.N.X;
// @Filename: /node_modules/b/node_modules/x/index.d.ts
export namespace G {
namespace M {
class X {
private x: number;
}
}
namespace N {
class X {
private x: number;
}
}
}
// @Filename: /src/a.ts
import { an, useMX, useNX } from "a";
import { bm, bn } from "b";
// Works:
useMX(bm);
useNX(bn);
// Error:
useMX(an);
useMX(bn);

View file

@ -0,0 +1,38 @@
// @Filename: /node_modules/a/index.d.ts
import X from "x";
export function a(x: X): void;
// @Filename: /node_modules/a/node_modules/x/index.d.ts
export default class X {
protected m(): void;
private x: number;
}
// @Filename: /node_modules/b/index.d.ts
import X from "x";
export const b: X;
// @Filename: /node_modules/b/node_modules/x/index.d.ts
export default class X {
protected m(): void;
private x: number;
// OK to provide more members
private y: number;
}
// @Filename: /node_modules/c/index.d.ts
import X from "x";
export const c: X;
// @Filename: /node_modules/c/node_modules/x/index.d.ts
export default class X {
protected m(): void;
// Not OK to be missing a member
}
// @Filename: /src/a.ts
import { a } from "a";
import { b } from "b";
import { c } from "c";
a(b);
a(c); // Error

View file

@ -0,0 +1,23 @@
// @Filename: /node_modules/a/index.d.ts
import X = require("x");
export { X as A };
// @Filename: /node_modules/a/node_modules/x/index.d.ts
export = class {
private m(): void;
}
// @Filename: /node_modules/b/index.d.ts
import X = require("x");
export { X as B };
// @Filename: /node_modules/b/node_modules/x/index.d.ts
export = class {
private m(): void;
}
// @Filename: /src/a.ts
import { A } from "a";
import { B } from "b";
let a = new A();
a = new B();

View file

@ -0,0 +1,15 @@
// @Filename: /node_modules/a/c0.d.ts
export class C {
private m(): void;
}
// @Filename: /node_modules/a/c1.d.ts
export class C {
private m(): void;
}
// @Filename: /src/a.ts
import { C as C0 } from "a/c0";
import { C as C1 } from "a/c1";
let c = new C0();
c = new C1();