[types] Hand-maintain StyleXCSSTypes.d.ts for autocompletable unions - #1882
Draft
henryqdineen wants to merge 1 commit into
Draft
henryqdineen wants to merge 1 commit into
henryqdineen wants to merge 1 commit into
Conversation
workflow: benchmarks/sizeComparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.
|
workflow: benchmarks/perfComparison of performance test results, measured in operations per second. Larger is better.
|
henryqdineen
added this pull request to stack #1887
September 11, 2026 03:13
`gen-types` translates the Flow types into TypeScript, which loses the most
useful thing these types can do, because a Flow union containing `string`
collapses to `string` and discards every literal member:
Flow: type Display = 'block' | 'flex' | string;
TypeScript: type Display = 'block' | 'flex' | (string & {});
`string & {}` is mutually assignable with `string`, so any string is still
accepted, but the literals survive and editors keep suggesting them. There is
no way to express this in Flow.
`gen-types` copies a `.d.ts` verbatim when one sits beside the Flow source, so
checking this file in is enough to take over that translation -- no build
changes. Verified byte-identical to what `gen-types` produced, once the 249
`string` -> `(string & {})` substitutions are reversed.
100 of the 522 properties were typed as bare `string` or `number | string` and
so offered no completions at all; another ~340 lost their literals to a
`string` member. Those now autocomplete.
`packages/typescript-tests/src/open-unions.ts` covers the behaviour: arbitrary
strings and `var()` are still accepted, `null` still unsets a property, the
CSS-wide keywords still resolve, literals survive, and closed unions stay
closed. Note `NonNullable` cannot be used to inspect these unions -- it is
`T & {}` in TypeScript >=4.9, and that intersection flattens them.
The two files must now be kept in sync by hand. Adding a css-tree-based test to
enforce that, and to check the literals against the CSS grammar, is the
intended follow-up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
henryqdineen
force-pushed
the
hqd-stylex-css-types-dts
branch
from
September 11, 2026 03:15
98ae19c to
6d988f8
Compare
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed / motivation ?
First of five stacked PRs on
CSSProperties. The goal across them is to make the CSS types more useful, more complete, and more correct. Useful, because a union that accepts any string currently offers no autocomplete at all. Complete, because 522 properties and ~2,500 keywords written by hand have drifted from CSS. Correct, because some of what is there is wrong — every property was missingrevert, and six accept no CSS-wide keywords at all, socolorScheme: 'inherit'is a type error today.They are ordered so each one enables the next: the autocompletable definitions come first, then the tests that check them against CSS, then the fixes those tests found.
StyleXCSSTypes.d.ts, so unions keep their literalsrevertandrevert-layer; fix the six properties that accept no CSS-wide keywordscursorshould accepturl()values (#1463)Only the first two are infrastructure; 3 and 4 are bugs the tests found, and both are pure widenings.
This answers the question I asked in #1466: yes, maintaining a separate TypeScript definition of the CSS types is worth it, because the thing it enables cannot be expressed in Flow at all.
gen-typestranslates the Flow types into TypeScript, and that translation throws away the most useful thing these types can do, because a Flow union containingstringcollapses tostringand discards every literal member:string & {}is mutually assignable withstring, so any string is still accepted, but the literals survive and editors keep suggesting them. (The trick explained.)gen-typescopies a.d.tsverbatim when one sits beside the Flow source, so checking this file in is enough to take over that translation. No build changes are needed.100 of the 522 properties were typed as a bare
stringornumber | string, so they offered no completions at all; roughly 340 more lost their literals to astringmember. Those now autocomplete.Linked PR/Issues
Answers the question raised in #1466.
Additional Context
The diff is deliberately minimal. This file is byte-identical to what
gen-typesalready produced, once the 249string→(string & {})substitutions are reversed. There are no type changes to audit: no properties added or removed, no keywords added or removed, nothing widened, nothing narrowed. Everystringin the file is a plain union member or type-alias body — no index signatures, noRecord<string, …>, no template literals, no generic arguments — so the substitution is mechanical.Not a breaking change, and not a behavioural one. The unions that now end in
(string & {})previously ended in a barestring, which already accepted any string. Nothing new is accepted and nothing that typechecked before stops; the only change is that the literals are no longer erased.packages/typescript-tests/src/open-unions.tscovers the behaviour: arbitrary strings andvar()are still accepted,nullstill unsets a property, the CSS-wide keywords still resolve, literals survive, and closed unions stay closed.One trap if you extend those tests: do not use
NonNullableto inspect these unions. It isT & {}in TypeScript >= 4.9, and that intersection flattens them back down tostring— so a test written with it will pass whether or not the literals actually survived, which is exactly the thing being tested. My first version of these tests had that bug.The two files must now be kept in sync by hand. The next PR in this stack adds tests that enforce it — and writing those turned up a fair amount in the existing types that is incomplete, inconsistent, or simply wrong.
Pre-flight checklist
Contribution Guidelines
🤖 Generated with Claude Code