Skip to content

Commit 6cf1af2

Browse files
silverwindclaudeRobinMalfait
authored
Fix TS2742 error when inferring exported Config type (#19707)
Type aliases get resolved through to `UserConfig` during declaration emit, which lives in a hashed internal DTS chunk with no stable import path, causing TS2742. This is 100% backwards-compatible because type aliases and interfaces are structurally comparable. Fixes: #15844 Fixes: #19706 Fixes: #15458 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
1 parent f036f80 commit 6cf1af2

5 files changed

Lines changed: 156 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- Canonicalization: migrate arbitrary `:has()` variants from `[&:has(…)]` to `has-[…]` ([#19991](https://github.com/tailwindlabs/tailwindcss/pull/19991))
2424
- Upgrade: don’t migrate inline `style` attributes ([#19918](https://github.com/tailwindlabs/tailwindcss/pull/19918))
2525
- Allow multiple `@utility` definitions with the same name but different value types ([#19777](https://github.com/tailwindlabs/tailwindcss/pull/19777))
26+
- Export missing `PluginWithConfig` type from `tailwindcss/plugin` to fix errors when inferring plugin config types ([#19707](https://github.com/tailwindlabs/tailwindcss/pull/19707))
2627

2728
## [4.2.4] - 2026-04-21
2829

integrations/cli/config.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,72 @@ test(
126126
},
127127
)
128128

129+
// https://github.com/tailwindlabs/tailwindcss/issues/19706
130+
test(
131+
'Config files (TS, valid types)',
132+
{
133+
fs: {
134+
'package.json': json`
135+
{
136+
"type": "module",
137+
"dependencies": {
138+
"tailwindcss": "workspace:^",
139+
"@tailwindcss/cli": "workspace:^"
140+
},
141+
"devDependencies": {
142+
"typescript": "^5.9.3"
143+
}
144+
}
145+
`,
146+
'tsconfig.json': json`
147+
{
148+
"compilerOptions": {
149+
"target": "ES2022",
150+
"module": "NodeNext",
151+
"moduleResolution": "NodeNext",
152+
"declaration": true,
153+
"composite": true,
154+
"outDir": "./.build",
155+
"skipLibCheck": true
156+
},
157+
"include": ["tailwind.config.ts"]
158+
}
159+
`,
160+
'index.html': html`
161+
<div class="text-primary"></div>
162+
`,
163+
'tailwind.config.ts': ts`
164+
import type { Config } from 'tailwindcss'
165+
166+
function defineConfig(config: Config): Config {
167+
return config
168+
}
169+
170+
export default defineConfig({
171+
theme: {
172+
extend: {
173+
colors: {
174+
primary: 'blue',
175+
},
176+
},
177+
},
178+
})
179+
`,
180+
'src/index.css': css`
181+
@import 'tailwindcss';
182+
@config '../tailwind.config.ts';
183+
`,
184+
},
185+
},
186+
async ({ fs, exec }) => {
187+
// We expect that these commands don't crash:
188+
await exec('pnpm tsc -b')
189+
await exec('pnpm tailwindcss --input src/index.css --output dist/out.css')
190+
191+
await fs.expectFileToContain('dist/out.css', [candidate`text-primary`])
192+
},
193+
)
194+
129195
test(
130196
'Config files (CJS, watch mode)',
131197
{

integrations/cli/plugins.test.ts

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { candidate, css, html, json, test } from '../utils'
1+
import { candidate, css, html, json, test, ts } from '../utils'
22

33
test(
44
'builds the `@tailwindcss/typography` plugin utilities',
@@ -207,3 +207,88 @@ test(
207207
])
208208
},
209209
)
210+
211+
// https://github.com/tailwindlabs/tailwindcss/issues/15844
212+
test(
213+
'builds CSS with a custom plugin compiled from TypeScript',
214+
{
215+
fs: {
216+
'package.json': json`
217+
{
218+
"type": "module",
219+
"dependencies": {
220+
"tailwindcss": "workspace:^",
221+
"@tailwindcss/cli": "workspace:^"
222+
},
223+
"devDependencies": {
224+
"typescript": "^5.7.2"
225+
}
226+
}
227+
`,
228+
'tsconfig.json': json`
229+
{
230+
"compilerOptions": {
231+
"target": "ES2022",
232+
"module": "NodeNext",
233+
"moduleResolution": "NodeNext",
234+
"declaration": true,
235+
"composite": true,
236+
"rootDir": "./src",
237+
"outDir": "./.build",
238+
"skipLibCheck": true
239+
},
240+
"include": ["src/**/*.ts"]
241+
}
242+
`,
243+
'index.html': html`
244+
<div class="test-red"></div>
245+
`,
246+
'src/index.css': css`
247+
@import 'tailwindcss';
248+
@plugin '../.build/plugin.js';
249+
`,
250+
'src/plugin.ts': ts`
251+
import plugin from 'tailwindcss/plugin'
252+
253+
export const typedPlugin = plugin(() => {
254+
return ({ matchComponents }) => {
255+
matchComponents(
256+
{
257+
test: (content: string) => ({
258+
color: content,
259+
}),
260+
},
261+
{
262+
values: {
263+
red: 'red',
264+
},
265+
},
266+
)
267+
}
268+
})
269+
270+
export default plugin(({ matchComponents }) => {
271+
matchComponents(
272+
{
273+
test: (content: string) => ({
274+
color: content,
275+
}),
276+
},
277+
{
278+
values: {
279+
red: 'red',
280+
},
281+
},
282+
)
283+
})
284+
`,
285+
},
286+
},
287+
async ({ fs, exec }) => {
288+
// We expect that these commands don't crash:
289+
await exec('pnpm tsc -b')
290+
await exec('pnpm tailwindcss --input src/index.css --output dist/out.css')
291+
292+
await fs.expectFileToContain('dist/out.css', [candidate`test-red`])
293+
},
294+
)

packages/tailwindcss/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import { segment } from './utils/segment'
3434
import { topologicalSort } from './utils/topological-sort'
3535
import { compoundsForSelectors, IS_VALID_VARIANT_NAME, substituteAtVariant } from './variants'
3636
import { walk, WalkAction } from './walk'
37-
export type Config = UserConfig
37+
38+
export interface Config extends UserConfig {}
3839

3940
const IS_VALID_PREFIX = /^[a-z]+$/
4041

packages/tailwindcss/src/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@ export type {
4141
PluginFn as PluginCreator,
4242
Plugin as PluginsConfig,
4343
PluginUtils,
44+
PluginWithConfig,
4445
ThemeConfig,
4546
}

0 commit comments

Comments
 (0)