]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(types): more precise types for class bindings (#8012)
authorBasil Gor <vasiliy.goryachev@lightspeedhq.com>
Fri, 10 Nov 2023 07:15:54 +0000 (23:15 -0800)
committerGitHub <noreply@github.com>
Fri, 10 Nov 2023 07:15:54 +0000 (15:15 +0800)
packages/dts-test/tsx.test-d.tsx
packages/runtime-dom/src/jsx.ts
packages/shared/__tests__/normalizeProp.spec.ts

index a15d16ac4d225c6c775c49bf5b96cf9245591d10..4b4a0dbf9df92518d5beb3dd026e65e2b341fa66 100644 (file)
@@ -17,6 +17,42 @@ expectType<JSX.Element>(
   <div style={[{ color: 'red' }, [{ fontSize: '1em' }]]} />
 )
 
+// allow undefined, string, object, array and nested array classes
+expectType<JSX.Element>(<div class={undefined} />)
+expectType<JSX.Element>(<div class={'foo'} />)
+expectType<JSX.Element>(<div class={['foo', undefined, 'bar']} />)
+expectType<JSX.Element>(<div class={[]} />)
+expectType<JSX.Element>(<div class={['foo', ['bar'], [['baz']]]} />)
+expectType<JSX.Element>(<div class={{ foo: true, bar: false, baz: true }} />)
+expectType<JSX.Element>(<div class={{}} />)
+expectType<JSX.Element>(
+  <div class={['foo', ['bar'], { baz: true }, [{ qux: true }]]} />
+)
+expectType<JSX.Element>(
+  <div
+    class={[
+      { foo: false },
+      { bar: 0 },
+      { baz: -0 },
+      { qux: '' },
+      { quux: null },
+      { corge: undefined },
+      { grault: NaN }
+    ]}
+  />
+)
+expectType<JSX.Element>(
+  <div
+    class={[
+      { foo: true },
+      { bar: 'not-empty' },
+      { baz: 1 },
+      { qux: {} },
+      { quux: [] }
+    ]}
+  />
+)
+
 // #7955
 expectType<JSX.Element>(<div style={[undefined, '', null, false]} />)
 
index dfa4fc561c67103151b47a042c988b2ce1e433af..580fa9300fbad13f87b3bddf149aee066dc11562 100644 (file)
@@ -252,10 +252,16 @@ export type StyleValue =
   | CSSProperties
   | Array<StyleValue>
 
+export type ClassValue =
+  | undefined
+  | string
+  | Record<string | number, unknown>
+  | Array<ClassValue>
+
 export interface HTMLAttributes extends AriaAttributes, EventHandlers<Events> {
   innerHTML?: string
 
-  class?: any
+  class?: ClassValue
   style?: StyleValue
 
   // Standard HTML Attributes
index a3cb104c003f434345ff2f5fefd5a93b671a5f6c..bf9cf7e33be1df36460d143cc36d11483452fb1d 100644 (file)
@@ -1,6 +1,10 @@
 import { normalizeClass, parseStringStyle } from '../src'
 
 describe('normalizeClass', () => {
+  test('handles undefined correctly', () => {
+    expect(normalizeClass(undefined)).toEqual('')
+  })
+
   test('handles string correctly', () => {
     expect(normalizeClass('foo')).toEqual('foo')
   })
@@ -11,12 +15,56 @@ describe('normalizeClass', () => {
     )
   })
 
+  test('handles empty array correctly', () => {
+    expect(normalizeClass([])).toEqual('')
+  })
+
+  test('handles nested array correctly', () => {
+    expect(normalizeClass(['foo', ['bar'], [['baz']]])).toEqual('foo bar baz')
+  })
+
   test('handles object correctly', () => {
     expect(normalizeClass({ foo: true, bar: false, baz: true })).toEqual(
       'foo baz'
     )
   })
 
+  test('handles empty object correctly', () => {
+    expect(normalizeClass({})).toEqual('')
+  })
+
+  test('handles arrays and objects correctly', () => {
+    expect(
+      normalizeClass(['foo', ['bar'], { baz: true }, [{ qux: true }]])
+    ).toEqual('foo bar baz qux')
+  })
+
+  test('handles array of objects with falsy values', () => {
+    expect(
+      normalizeClass([
+        { foo: false },
+        { bar: 0 },
+        { baz: -0 },
+        { qux: '' },
+        { quux: null },
+        { corge: undefined },
+        { grault: NaN }
+      ])
+    ).toEqual('')
+  })
+
+  test('handles array of objects with truthy values', () => {
+    expect(
+      normalizeClass([
+        { foo: true },
+        { bar: 'not-empty' },
+        { baz: 1 },
+        { qux: {} },
+        { quux: [] }
+      ])
+    ).toEqual('foo bar baz qux quux')
+  })
+
   // #6777
   test('parse multi-line inline style', () => {
     expect(