Skip to content

@type {const} produces namespace in .d.ts instead of normal object typeΒ #56789

Description

πŸ”Ž Search Terms

@type {const}
const
definition types

πŸ•— Version & Regression Information

  • This is a crash in all versions

⏯ Playground Link

https://www.typescriptlang.org/play?target=99&jsx=0&ts=5.3.2&filetype=ts#code/KYDwDg9gTgLgBAYwgOwM7wLYE8DCL1wC8cA9AFRlwACMWYwcA3kmjAL5xklMCwAUAEgAZhAgAuOAHIARgEMokgDT9hAV1UTGK4aIkz5klW35sA3PyA

πŸ’» Code

// Typescript file
export const myConst = /** @type {const} */ {
	foo: 'bar',
	fuu: {
		foo: 'bar'
	}
};
// Javascript file
export const myConst = /** @type {const} */ {
	foo: 'bar',
	fuu: {
		foo: 'bar'
	}
};

πŸ™ Actual behavior

// .D.TS from Typescript file
export declare const myConst: {
    foo: string;
    fuu: {
        foo: string;
    };
};
// .D.TS from Javascript file
export namespace myConst {
    let foo: string;
    namespace fuu {
        let foo_1: string;
        export { foo_1 as foo };
    }
}

πŸ™‚ Expected behavior

Same output in both cases. Typescript file output is the correct one.

Additional information about the issue

No response

Activity

  1. changed the title [-]@const emit different definition types from Javascript and Typescript files[/-] [+]`@type {const}` emit different definition types from Javascript and Typescript files[/+] on Dec 15, 2023
  2. fatcerberus commented on Dec 15, 2023

    @fatcerberus

    The @type {const} doesn't seem to be relevant - the .js produces the same output whether it's present or not.

    Note that TS ignores type info in JSDoc comments when processing .ts files.

  3. jorgecasar commented on Dec 20, 2023

    @jorgecasar
    Author

    Form typescript documentation: You can even cast to const just like TypeScript:

    let one = /** @type {const} */(1);

    I guess, same code in Typescript and Javascript should output same Javascript and same definition types files. And even more when you are typing Javascript code with jsdoc as Typescript supports

  4. RyanCavanaugh commented on Dec 21, 2023

    @RyanCavanaugh
    Member

    In TS files, you have to use TS syntax for type annotations / assertions. Producing identical .d.ts output from .ts and .js files is not an intended invariant.

  5. jorgecasar commented on Dec 22, 2023

    @jorgecasar
    Author

    Then, how can I annotate the JS file to get a constant declaration? I'm trying to expose types of a library to be able using it with Typescript and this is not what a Typescript developer expect for a const:

    export namespace myConst {
        let foo: string;
        namespace fuu {
            let foo_1: string;
            export { foo_1 as foo };
        }
    }
    

    In the other hand, based on your answer if I would like to move a project from js to ts could generate unexpected results during the migration. I thought that Typescript was a superset of Javascript, and same code should producing same output.

  6. changed the title [-]`@type {const}` emit different definition types from Javascript and Typescript files[/-] [+]`@type {const}` produces namespace in .d.ts instead of normal object type[/+] on Dec 22, 2023
  7. RyanCavanaugh commented on Dec 22, 2023

    @RyanCavanaugh
    Member

    The are sort of two issues being implied here:

    • TS and JS .d.ts output should be identical -- again, this is not an invariant
    • JS .d.ts is producing a weird namespace declaration when it could just be a const - this should be changed
  8. sandersn commented on Dec 27, 2023

    @sandersn
    Member

    I think there are two smaller repro pairs that are relevant.

    Equivalence of 'as const':

    export const a_ts = { foo: 'bar' } as const
    export const a_js = /** @type {const} */({ foo: 'bar' })

    Both a_ts and a_js should have type { readonly foo: 'bar' } not { foo: string }. Quick info shows that they do, so there's no bug here.

    Equivalence of const object-literal:

    export const b_ts = { foo: 'bar' }
    export const b_js = { foo: 'bar' }

    Both b_ts and b_js should generate export declare const b_ts: { foo: string } But b_js generates

    export namespace b_js {
      let foo: string
    }

    This is the bug; the rest of the export { foo_1 as foo } in the longer examples are renaming shenanigans that are required for a namespace (as far as I know off the top of my head).

    I'm pretty sure this is a result of const x = { object: "literal" } being tagged as an assignment declaration, so the fix is likely either a design change in the binder or a workaround in declaration emit (where the workaround is essentially "this looks special but there's only one declaration, so treat it normally after all").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptDomain: JSDocRelates to JSDoc parsing and type generationRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions