Skip to content

Commit bbb8977

Browse files
authored
fix(types): narrow useAttrs class/style typing for TSX (#14492)
close #14489
1 parent 740983e commit bbb8977

File tree

5 files changed

+37
-6
lines changed

5 files changed

+37
-6
lines changed

packages-private/dts-test/tsx.test-d.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
// TSX w/ defineComponent is tested in defineComponent.test-d.tsx
2-
import { Fragment, KeepAlive, Suspense, Teleport, type VNode } from 'vue'
2+
import {
3+
Fragment,
4+
KeepAlive,
5+
Suspense,
6+
Teleport,
7+
type VNode,
8+
useAttrs,
9+
} from 'vue'
310
import { expectType } from './utils'
411

512
expectType<VNode>(<div />)
@@ -54,6 +61,14 @@ expectType<JSX.Element>(
5461
/>,
5562
)
5663

64+
// allow class/style passthrough from attrs
65+
const attrs = useAttrs()
66+
expectType<JSX.Element>(<div class={attrs.class} />)
67+
expectType<JSX.Element>(<div style={attrs.style} />)
68+
69+
// @ts-expect-error invalid class value
70+
;<div class={0} />
71+
5772
// #7955
5873
expectType<JSX.Element>(<div style={[undefined, '', null, false]} />)
5974

packages/runtime-core/src/component.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ import type { RendererElement } from './renderer'
9898

9999
export type Data = Record<string, unknown>
100100

101+
/**
102+
* For extending allowed non-declared attrs on components in TSX
103+
*/
104+
export interface AllowedAttrs {}
105+
106+
export type Attrs = Data & AllowedAttrs
107+
101108
/**
102109
* Public utility type for extracting the instance type of a component.
103110
* Works with all valid component definition types. This is intended to replace
@@ -283,7 +290,7 @@ export type SetupContext<
283290
S extends SlotsType = {},
284291
> = E extends any
285292
? {
286-
attrs: Data
293+
attrs: Attrs
287294
slots: UnwrapSlotsType<S>
288295
emit: EmitFn<E>
289296
expose: <Exposed extends Record<string, any> = Record<string, any>>(
@@ -1152,13 +1159,13 @@ export function createSetupContext(
11521159
if (__DEV__) {
11531160
// We use getters in dev in case libs like test-utils overwrite instance
11541161
// properties (overwrites should not be done in prod)
1155-
let attrsProxy: Data
1162+
let attrsProxy: Attrs
11561163
let slotsProxy: Slots
11571164
return Object.freeze({
11581165
get attrs() {
11591166
return (
11601167
attrsProxy ||
1161-
(attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers))
1168+
(attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers) as Attrs)
11621169
)
11631170
},
11641171
get slots() {
@@ -1171,7 +1178,7 @@ export function createSetupContext(
11711178
})
11721179
} else {
11731180
return {
1174-
attrs: new Proxy(instance.attrs, attrsProxyHandlers),
1181+
attrs: new Proxy(instance.attrs, attrsProxyHandlers) as Attrs,
11751182
slots: instance.slots,
11761183
emit: instance.emit,
11771184
expose,

packages/runtime-core/src/componentPublicInstance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
type Attrs,
23
type Component,
34
type ComponentInternalInstance,
45
type Data,
@@ -306,7 +307,7 @@ export type ComponentPublicInstance<
306307
$props: MakeDefaultsOptional extends true
307308
? Partial<Defaults> & Omit<Prettify<P> & PublicProps, keyof Defaults>
308309
: Prettify<P> & PublicProps
309-
$attrs: Data
310+
$attrs: Attrs
310311
$refs: Data & TypeRefs
311312
$slots: UnwrapSlotsType<S>
312313
$root: ComponentPublicInstance | null

packages/runtime-core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,9 @@ export type {
259259
ConcreteComponent,
260260
FunctionalComponent,
261261
ComponentInternalInstance,
262+
Attrs,
262263
SetupContext,
264+
AllowedAttrs,
263265
ComponentCustomProps,
264266
AllowedComponentProps,
265267
GlobalComponents,

packages/runtime-dom/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import type { TransitionGroupProps } from './components/TransitionGroup'
3333
import type { vShow } from './directives/vShow'
3434
import type { VOnDirective } from './directives/vOn'
3535
import type { VModelDirective } from './directives/vModel'
36+
import type { ClassValue, StyleValue } from './jsx'
3637

3738
/**
3839
* This is a stub implementation to prevent the need to use dom types.
@@ -48,6 +49,11 @@ declare module '@vue/reactivity' {
4849
}
4950

5051
declare module '@vue/runtime-core' {
52+
interface AllowedAttrs {
53+
class?: ClassValue
54+
style?: StyleValue
55+
}
56+
5157
interface GlobalComponents {
5258
Transition: DefineComponent<TransitionProps>
5359
TransitionGroup: DefineComponent<TransitionGroupProps>

0 commit comments

Comments
 (0)