]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types: improve createElement typing
authorEvan You <yyx990803@gmail.com>
Fri, 12 Oct 2018 23:49:41 +0000 (19:49 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 12 Oct 2018 23:49:41 +0000 (19:49 -0400)
.vscode/settings.json
packages/core/__tests__/attrsFallthrough.spec.ts
packages/core/src/component.ts
packages/core/src/componentOptions.ts
packages/core/src/h.ts
packages/core/src/optional/mixin.ts
packages/core/src/vdom.ts
packages/renderer-dom/src/patchData.ts

index 50f76ba3975e2a509a513ad17883593a2ba7006d..bb531a850102fda34c7797f93a9fb6aeec790857 100644 (file)
@@ -22,7 +22,6 @@
     "rust",
     "scss",
     "text",
-    "typescriptreact",
     "yml"
   ]
 }
index 41bf51bd529f881d09301784fa540c95ddd61aab..68740cc24cbaa6fa0cf1440d636ccf3336cd0d25 100644 (file)
@@ -6,12 +6,8 @@ describe('attribute fallthrough', () => {
     const click = jest.fn()
     const childUpdated = jest.fn()
 
-    class Hello extends Component<{}, { count: number }> {
-      data() {
-        return {
-          count: 0
-        }
-      }
+    class Hello extends Component {
+      count: number = 0
       inc() {
         this.count++
         click()
@@ -27,7 +23,7 @@ describe('attribute fallthrough', () => {
       }
     }
 
-    class Child extends Component {
+    class Child extends Component<{ [key: string]: any }> {
       updated() {
         childUpdated()
       }
@@ -73,19 +69,15 @@ describe('attribute fallthrough', () => {
     const click = jest.fn()
     const childUpdated = jest.fn()
 
-    class Hello extends Component<{}, { count: number }> {
-      data() {
-        return {
-          count: 0
-        }
-      }
+    class Hello extends Component {
+      count = 0
       inc() {
         this.count++
         click()
       }
       render() {
         return h(Child, {
-          foo: 1,
+          foo: 123,
           id: 'test',
           class: 'c' + this.count,
           style: { color: this.count ? 'red' : 'green' },
@@ -94,7 +86,7 @@ describe('attribute fallthrough', () => {
       }
     }
 
-    class Child extends Component<{ foo: number }> {
+    class Child extends Component<{ [key: string]: any; foo: number }> {
       static props = {
         foo: Number
       }
@@ -148,12 +140,8 @@ describe('attribute fallthrough', () => {
     const childUpdated = jest.fn()
     const grandChildUpdated = jest.fn()
 
-    class Hello extends Component<{}, { count: number }> {
-      data() {
-        return {
-          count: 0
-        }
-      }
+    class Hello extends Component {
+      count = 0
       inc() {
         this.count++
         click()
@@ -169,7 +157,7 @@ describe('attribute fallthrough', () => {
       }
     }
 
-    class Child extends Component {
+    class Child extends Component<{ [key: string]: any; foo: number }> {
       updated() {
         childUpdated()
       }
@@ -178,7 +166,7 @@ describe('attribute fallthrough', () => {
       }
     }
 
-    class GrandChild extends Component<{ foo: number }> {
+    class GrandChild extends Component<{ [key: string]: any; foo: number }> {
       static props = {
         foo: Number
       }
index 66fc4bb0c319a740cfebde5ddf1c2fdba8cd1853..394bf9844967226a0f164995e0bbf39a622ac1f4 100644 (file)
@@ -13,9 +13,9 @@ import { nextTick } from '@vue/scheduler'
 import { ErrorTypes } from './errorHandling'
 import { initializeComponentInstance } from './componentUtils'
 
-export interface ComponentClass extends ComponentClassOptions {
+export interface ComponentClass<P = {}> extends ComponentClassOptions {
   options?: ComponentOptions
-  new <P = {}, D = {}>(): MergedComponent<P, D>
+  new <P = {}, D = {}>(props?: P): MergedComponent<P, D>
 }
 
 export type MergedComponent<P, D> = D & P & ComponentInstance<P, D>
index 690daab14c51f8a517bf5bebe44d00d4cb90860f..08cf83c86e61bc999afdc8421a43cba4b31f4bad 100644 (file)
@@ -1,18 +1,18 @@
-import { ComponentInstance } from './component'
+import { ComponentInstance, MergedComponent } from './component'
 import { Slots } from './vdom'
 
 export type Data = Record<string, any>
 
-export interface ComponentClassOptions<This = ComponentInstance> {
-  props?: ComponentPropsOptions
+export interface ComponentClassOptions<P = {}, This = ComponentInstance> {
+  props?: ComponentPropsOptions<P>
   computed?: ComponentComputedOptions<This>
   watch?: ComponentWatchOptions<This>
   displayName?: string
 }
 
-export interface ComponentOptions<This = ComponentInstance>
-  extends ComponentClassOptions<This> {
-  data?(): object
+export interface ComponentOptions<P = {}, D = {}, This = MergedComponent<P, D>>
+  extends ComponentClassOptions<P, This> {
+  data?(): D
   render?: (this: This, props: Readonly<Data>, slots: Slots, attrs: Data) => any
   // TODO other options
   readonly [key: string]: any
index 29c7d235c0df7c8f9d0115598bfa7c91b63a0b86..c461017d1a9356e20ce86ebc3efdf1374195caa9 100644 (file)
@@ -2,7 +2,6 @@ import { ChildrenFlags } from './flags'
 import {
   ComponentClass,
   FunctionalComponent,
-  Component,
   ComponentInstance
 } from './component'
 import { ComponentOptions } from './componentOptions'
@@ -14,7 +13,8 @@ import {
   createFragment,
   createPortal,
   VNodeData,
-  BuiltInProps
+  BuiltInProps,
+  Key
 } from './vdom'
 import { isObservable } from '@vue/observer'
 import { warn } from './warning'
@@ -22,6 +22,14 @@ import { warn } from './warning'
 export const Fragment = Symbol()
 export const Portal = Symbol()
 
+type RawChildType = VNode | string | number | boolean | null | undefined
+
+export type RawSlots = {
+  [name: string]: () => RawChildrenType
+}
+
+export type RawChildrenType = RawChildType | RawChildType[]
+
 export type ElementType =
   | string
   | FunctionalComponent
@@ -30,10 +38,6 @@ export type ElementType =
   | typeof Fragment
   | typeof Portal
 
-type RawChildType = VNode | string | number | boolean | null | undefined
-
-export type RawChildrenType = RawChildType | RawChildType[]
-
 interface VNodeFactories {
   c: typeof createComponentVNode
   e: typeof createElementVNode
@@ -42,20 +46,60 @@ interface VNodeFactories {
   p: typeof createPortal
 }
 
-interface createElement {
+// This is used to differentiate the data object from
+// vnodes and arrays
+type Differ = { _isVNode?: never; [Symbol.iterator]?: never }
+
+type OptionsComponent<P> =
+  | (ComponentOptions<P> & { template: string })
+  | (ComponentOptions<P> & { render: Function })
+
+interface createElement extends VNodeFactories {
   // element
-  (tag: string, data?: VNodeData, children?: any): VNode
+  (
+    tag: string,
+    // TODO support native element properties
+    data?: VNodeData & Differ | null,
+    children?: RawChildrenType | RawSlots
+  ): VNode
+  (tag: string, children?: RawChildrenType): VNode
+  // fragment
+  (
+    tag: typeof Fragment,
+    data?: ({ key?: Key } & Differ) | null,
+    children?: RawChildrenType | RawSlots
+  ): VNode
+  (tag: typeof Fragment, children?: RawChildrenType): VNode
+  // portal
+  (
+    tag: typeof Portal,
+    data?: ({ target: any } & BuiltInProps & Differ) | null,
+    children?: RawChildrenType | RawSlots
+  ): VNode
+  (tag: typeof Portal, children?: RawChildrenType): VNode
+  // object
+  <P>(
+    tag: OptionsComponent<P>,
+    data?: (P & BuiltInProps & Differ) | null,
+    children?: RawChildrenType | RawSlots
+  ): VNode
+  <P>(tag: OptionsComponent<P>, children?: RawChildrenType): VNode
   // functional
   <P>(
     tag: FunctionalComponent<P>,
-    data?: P & BuiltInProps | null,
-    children?: any
+    data?: (P & BuiltInProps & Differ) | null,
+    children?: RawChildrenType | RawSlots
+  ): VNode
+  <P>(tag: FunctionalComponent<P>, children?: RawChildrenType): VNode
+  // class
+  <P, T extends ComponentInstance<P>>(
+    tag: new () => T & { $props: P },
+    data?: (P & BuiltInProps & Differ) | null,
+    children?: RawChildrenType | RawSlots
   ): VNode
-  // stateful
   <P, T extends ComponentInstance<P>>(
     tag: new () => T & { $props: P },
-    data?: P & BuiltInProps | null,
-    children?: any
+    children?: RawChildrenType
   ): VNode
 }
 
@@ -138,7 +182,7 @@ export const h = ((tag: ElementType, data?: any, children?: any): VNode => {
       ref
     )
   }
-}) as createElement & VNodeFactories
+}) as createElement
 
 h.c = createComponentVNode
 h.e = createElementVNode
index 902d9f2ec916ab48fe5cc7b0630f29218f19056f..605075c0a801e4f84269899b6b1a3c6f76672db8 100644 (file)
@@ -1,16 +1,6 @@
-import { ComponentInstance, ComponentType } from '../component'
+import { ComponentInstance } from '../component'
 import { ComponentOptions } from '../componentOptions'
-import { RawVNodeChildren, VNodeData } from '../vdom'
 
 export interface Mixin extends ComponentOptions {}
 
 export function applyMixins(Component: ComponentInstance, mixins: Mixin[]) {}
-
-export function h(tag: ComponentType | string, data: RawVNodeChildren): object
-export function h(
-  tag: ComponentType | string,
-  data: VNodeData,
-  children: RawVNodeChildren
-): object {
-  return {}
-}
index f54fe3b136e8fc7a75a28e72ea728933aee44ffa..811f7b26080fa1cc8785cff1d34ace07339da49a 100644 (file)
@@ -6,7 +6,7 @@ import {
 import { VNodeFlags, ChildrenFlags } from './flags'
 import { createComponentClassFromOptions } from './componentUtils'
 import { normalizeClass, normalizeStyle, handlersRE, EMPTY_OBJ } from './utils'
-import { ElementType, RawChildrenType } from './h'
+import { RawChildrenType, RawSlots } from './h'
 
 // Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
 export interface RenderNode {
@@ -47,7 +47,9 @@ export interface BuiltInProps {
   slots?: RawSlots | null
 }
 
-export type VNodeData = Record<string, any> & BuiltInProps
+export type VNodeData = {
+  [key: string]: any
+} & BuiltInProps
 
 export type VNodeChildren =
   | VNode[] // ELEMENT | PORTAL
@@ -65,10 +67,6 @@ export type Slots = Readonly<{
   [name: string]: Slot
 }>
 
-export type RawSlots = {
-  [name: string]: () => RawChildrenType
-}
-
 export function createVNode(
   flags: VNodeFlags,
   tag: string | FunctionalComponent | ComponentClass | RenderNode | null,
index d13e8057884f70eb763758bc6ae5643bc72504e2..f6244cd470555a1717bd50076cf4bc436376b8fc 100644 (file)
@@ -7,8 +7,9 @@ import { patchEvent } from './modules/events'
 
 export const onRE = /^on/
 
-// value, checked, selected & muted are always patched as properties
-const domPropsRE = /^domProps|^(?:value|checked|selected|muted)$/
+// value, checked, selected & muted
+// plus anything with upperCase letter in it are always patched as properties
+const domPropsRE = /\W|^(?:value|checked|selected|muted)$/
 
 export function patchData(
   el: Element,