Description
Parentheses Changes Result of Conditional Type
- If you parenthesize the right side of the
extends
clause in a conditional type, it changes distributivity. - Tools like Prettier assume parentheses are purely stylistic unless it's meant to enforce precedence. They will remove them, which can change the meaning.
- Claimed this was intentional; however, our docs only mention using
[]
to avoid distributivity. - Bracketing just falls out of the general rules of "distributivity only happens on naked type variables".
- We added an optimization for
[]
, but parentheses were affected. - That seems unrelated!
- We added an optimization for
- Can we just get a more minimal repro?
- Hard to get, need to work on this.
- Let's recategorize as a bug, discuss further to ensure we're all on the same page.
Ambient module declarations for import assertions
import styles from "./styles.css" with { type: "css" };
document.adoptedStyleSheets = [...document.adoptedStyleSheets, styles];
-
Browsers have either shipped or indicate positive support for this feature.
-
What is it? Basically want to be able to import assets like
css
files and bring them in as default imports in the form ofCSSStyleSheet
objects. -
How do you convince TypeScript of this?
-
Maybe something like:
declare module "*" with { type: "css" } { declare const _default: CSSStyleSheet; export default _default; }
-
How does this work with merging? Multiple declarations? Fallbacks?
-
Maybe there needs to be a lookup strategy.
// globals.d.ts // No import attributes declare module "*.css" { declare const _default: CSSStyleSheet; export default _default; } // ... // Some modules // Has import attributes import styles from "./styles.css" with { type: "css" };
-
In other words, do
import styles from "./styles.css" with { type: "css" };
and
import styles from "./styles.css";
both resolve to the following declaration?
declare module "*.css" { declare const _default: CSSStyleSheet; export default _default; }
-
Why can't you get away with just always using a
*.css
pattern?- Bundlers and browsers decide on different behavior - or rather, bundlers decide differently.
-
Stepping back, pattern ambient modules really mask over everything. Kind of heavy-handed. You do want TypeScript to resolve the
.css
file on disk and validate that it's there, right? Usually? -
Want to express "what is my bundler going to do here?", and sometimes it is not best-served by what's in an ambient module, but rather what's on disk.
- You can express that with
.d.css.ts
files under some settings.
- You can express that with
-
What about something like
declare with { type: "css" } { declare const _default: CSSStyleSheet; export default _default; }
- Doesn't permit arbitrary paths for
*.css
imports, but does provide a well-understood shape.
- Doesn't permit arbitrary paths for
-
Doesn't this need a special resolution mode?
-
How does this affect emit?
- We don't emit
.json
files. - So we wouldn't copy over
.css
files from source?- No?
- That's weird.
- Mismatch between runtime and build time.
- What about
.d.css.ts
generation?
- We don't emit
-
How do
.json
imports work at all today?- Do people rarely do it?
- If it's not a problem for JSON, is it not a problem for CSS?
-
Wait, we do copy JSON to outputs?
- We coulda sworn we didn't...
- Well we re-emit the JSON, it's not a naive copy.
- We just don't overwrite the JSON if there's no
outDir
.
-
We do want a bit more context on how this should work in a larger project.
- Maybe Justin in the original issue can give context (at least in the context of maybe lit)?
-
Conclusions?
-
Revisit real resolution/emit for certain file types, plus import attribute-y ambient modules
declare with { type: "css" } { declare const _default: CSSStyleSheet; export default _default; }
-
Want to understand the full breadth of motivations
-