Repository navigation
Declaration emit cannot name an exported unique symbol property key unless the file already imports itΒ #64812
Description
π Search Terms
declaration emit, unique symbol, computed property, TS4023, cannot be named, spread, brand
π Version & Regression Information
Reproduced with typescript@6.0.3 and @typescript/native@7.0.2.
β― Playground Link
None. This needs declaration emit across two files. The full repro is below.
π» Code
// @filename: brand.ts
export declare const tag: unique symbol;
export type Branded<Type, Name extends string> = Type & {readonly [tag]: Name};
// @filename: index.ts
import type {Branded} from './brand.js';
declare const user: Branded<{name: string}, 'User'>;
export const copy = {...user};tsconfig.json:
{
"compilerOptions": {
"module": "nodenext",
"declaration": true,
"strict": true
}
}π Actual behavior
index.ts(5,14): error TS4023: Exported variable 'copy' has or is using name 'tag' from external module "/repro/brand" but cannot be named.
π Expected behavior
tag is exported from brand.ts, so there is a valid way to refer to it. I expected:
import type { tag } from './brand.js';
export declare const copy: {
name: string;
[tag]: "User";
};TypeScript emits exactly this today if I add tag to the import in index.ts, even though index.ts never uses it. So the emitter can produce valid output. It fails only because the name is not already in scope in the file.
Additional information about the issue
For other types, the emitter solves this with an import type, for example import("./brand.js").Branded<β¦>. A computed property key cannot use an import type, and declaration emit does not add import declarations. So a symbol key that the file does not already import can never be named.
This affects libraries that brand types with a unique symbol. For example, the Tagged type in type-fest uses a symbol key, and its users get this error when they spread an object, use rest destructuring, or map over an object type, and then export the result. The only workaround is to import the symbol in each such file and in every file that re-exports something derived from it. The error message does not hint at this. One type-fest user had to add this import to more than 50 files: sindresorhus/type-fest#1243
A possible fix: when declaration emit needs a unique symbol key that is exported from a module the file can reference, add an import type declaration for it, as in the expected output above.
Related:
./*.d.tsrequired inexportsto avoidCannot be named without a reference to... not portable...Β #60913 is about types that packageexportsmake unreachable. Here the symbol is exported and reachable.- Computed property invalid in type declaration emitted in d.ts fileΒ #60818 is about declaration emit writing an invalid computed key. Here the emitter reports an error instead.
Activity