Skip to content

types in transitive dependencies causing errors after upgrade from 3.1: The inferred type of ... cannot be named without a reference to #30858

Closed
@ravenscar

Description

@ravenscar

TypeScript Version: 3.4.3

Search Terms:
transitive dependency inferred type cannot be named without a reference
Code

Sorry that this is a Dockerfile, since the problem relates to multiple modules being installed as dependencies to each other it's difficult to express in a single piece of code. There's only 16 lines of code total, near as minimal as I could make it.

https://github.com/ravenscar/ts29221

docker build -t ts29221 https://raw.githubusercontent.com/ravenscar/ts29221/master/Dockerfile

Expected behavior:
tsc can compile the code

Actual behavior:
tsc fails with the messge:

src/index.ts(3,14): error TS2742: The inferred type of 'thingyTuple' cannot be named without a reference to '../../b/node_modules/ts29221-a/dist'. This is likely not portable. A type annotation is necessary.

This used to work fine in TS < 3.2 and seems to have broken since then, looking at the breaking changes I can't see anything mentioned which would apply here.

At first we thought we were experiencing issues due to symlinks created by lerna bootstrap and wanted to create an extremely minimal reproduction based on #29221, however we discovered that symlinks aren't the problem and have produced a Dockerfile to show that:

docker build -t ts29221 https://raw.githubusercontent.com/ravenscar/ts29221/master/DockerfileNoSymlinks

We also have a Dockerfile showing this working in 3.1:

docker build -t ts29221 https://raw.githubusercontent.com/ravenscar/ts29221/master/Dockerfile31

What happens here is that module ts29221-a exports a type definition, module ts29221-b uses that type definition in the return type of a function, then module ts29221-c uses that function to assign a value to a const.

This is using the new build system, with refs in the tsconfig, and is bootstrapped by lerna.

What is happening here is that when tsc is compiling ts29221-c it imports the types from ts29221-b which in turn imports them from ts29221-a. It then sees that they types are at a relative position of ../b/node_modules/ts29221-a/dist compared to ts29221-c's package.json.

They are actually also at node_modules/ts29221-b/node_modules/ts29221-a/dist relative to ts29221-c's package.json.

This is for example where they may be if they were installed by a package manager that didn't flatten dependencies (e.g. npm2 or pnpm).

The only way around this is for c to somehow know that b uses a and to add a as a direct dependency of c. Then to import the used type definition from a before importing b, even though c doesn't directly use a (so will need a tslint:ignore too).

Or do something even worse such as put this workaround at the top of c/src/index.ts:

import * as _ from '../node_modules/ts29221-b/node_modules/ts29221-a';

I think it is unreasonable for modules to need to know the dependencies of any of their submodules when it comes to types, although that is what we are currently doing in dozens of places.

I understand that the module resolution shows that it will only go up for node_modules but it really seems like something went wrong here as this pretty much makes TS broken for monorepos that use symlinks, if this is intentional then it's hard to imagine how the new build/watch features (which are awesome BTW) are supposed to work when the ts module dependencies are multiple levels deep.

Related Issues:
#29221
#29808
#26985

Metadata

Metadata

Assignees

Labels

Fix AvailableA PR has been opened for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions