GithubHelp home page GithubHelp logo

ESM `X.test` which have zero export statement, should be sub type of ESM `X` which have at least one export statement about typescript HOT 11 CLOSED

loynoir avatar loynoir commented on April 28, 2024
ESM `X.test` which have zero export statement, should be sub type of ESM `X` which have at least one export statement

from typescript.

Comments (11)

RyanCavanaugh avatar RyanCavanaugh commented on April 28, 2024

You have two modules shapes here:

  • The one from a, which has a foo: number property
  • The one from a.test, which has either nothing, nothing, or a default: {} property

The "nothing" variants supertype the { foo: number } property, so the union import(...) | import(...) gets reduced to the more-general of the two (nothing)

from typescript.

loynoir avatar loynoir commented on April 28, 2024

@RyanCavanaugh

But if a.test don't have export statement, I think it should be something like Record<string, never>.

Because the only way to let ESM module have X property, is using export statement.

If there is zero export statement, it means a zero key object Record<string, never>.

Right?


Change to a.test.mts

  • still get typeof import("/path/to/reproduce/a.test")

  • instead of something like {foo: 42} | Record<string, never>.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on April 28, 2024

That would be a very bad type; given x: Record<string, never> you can write nonsense like Math.sin(x.foo) without error

from typescript.

loynoir avatar loynoir commented on April 28, 2024

https://github.com/typescript-eslint/typescript-eslint/blob/609a0003663e0409f1d277a3f7649d17b98b5cdb/packages/eslint-plugin/src/rules/ban-types.ts#L101

Quote recommendation from @typescript-eslint/ban-types

If you want a type meaning "empty object", you probably want Record<string, never> instead.

from typescript.

fatcerberus avatar fatcerberus commented on April 28, 2024

The TypeScript maintainers have a... let's say... contentious relationship with the ban-types rule, specifically the part about it banning {}

Either way, Record<string, never> doesn't mean "empty object", regardless of what eslint recommends. It actually means "object where accessing any property throws an exception". Reading a property from an empty object doesn't give you a value of type never (i.e. an exception), it gives you undefined.

from typescript.

loynoir avatar loynoir commented on April 28, 2024

But, compared with {} which means any-alike, Record<string, never> seems to be yet the most correct type, to describe empty-object, maybe say always-zero-key-object, which describe an ESM module without any export statement.

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on April 28, 2024

If you want a type meaning "empty object", you probably want Record<string, never> instead.

The typescript-eslint maintainers are uncharacteristically super wrong about this. { } is a valid type with a valid meaning and it's just wrong for them to ban it. Unfortunately we haven't had much luck changing their minds.

from typescript.

JoshuaKGoldberg avatar JoshuaKGoldberg commented on April 28, 2024

👋 typescript-eslint maintainer here. The ban-types rule's default options were formed many years ago when TypeScript had less fleshed out rules around {}, object, and related. If there's evidence that the rule's options are now and/or always were wrong about something, we'd happily take an issue to improve them. The dev lead for TypeScript saying the rule is super wrong is pretty compelling evidence. 😄

Also looking at typescript-eslint/typescript-eslint#5018 (comment):

There's just a lot of confusion likely to come down the road on this specific ban in general, since we're likely to change the definition of NonNullable to T & { } in 4.8, and are already in 4.8 going to change the default narrowing rules such that a truthy narrowing of a value of an unconstrained type parameter becomes T & { }. Having typescript-eslint, out of the box, ban you from writing a type that TypeScript itself is inferring under totally normal operation, is awkward.

TypeScript did in fact ship the change to make type NonNullable<T> = T & {}; in #49119 - along with a host of other {} improvements. I'd wager that there's even more evidence we should revisit the ban.

Three related issues on our side:

For context: typescript-eslint is a separate maintenance team from TypeScript. Our opinions can sometimes fall out of sync with TypeScript best practices because we -like many independent open source projects- generally only take action in response to user prodding. We haven't been prodded about ban-types (that I know of) in quite a while. If there's anything ban-types or any other rule is doing that's out of sync with how TypeScript is meant to be, and TypeScript's handling of that rule's area has changed since the last time that rule was discussed, we'd happily take an issue prodding us to change. ❤️

from typescript.

loynoir avatar loynoir commented on April 28, 2024

As far as I see, maybe should split empty object type into another issue, if needed, as there are now two issue?

@JoshuaKGoldberg


The original issue is

Actual

ESM X.test which have zero export statement, is actually super type of ESM X which have at least one export statement

Expected

ESM X.test which have zero export statement, should be sub type of ESM X which have at least one export statement.

Because it is

  • zero-key-object-at-read

  • not zero-key-object-at-write, but consider as nop

> mod = await import('/tmp/empty-file.mjs')
> mod.x=1
1
> mod.x
undefined

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on April 28, 2024

There's no type in TypeScript that means "a type that is guaranteed to be completely empty" because TypeScript doesn't have sealed/exact types

from typescript.

typescript-bot avatar typescript-bot commented on April 28, 2024

This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

from typescript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.