types: use stricter defaults for component data and props

This commit is contained in:
Evan You 2018-10-04 17:33:20 -04:00
parent 05b70f790c
commit 511ac0bd2f
5 changed files with 29 additions and 19 deletions

View File

@ -6,7 +6,9 @@ describe('attribute fallthrough', () => {
const nativeClick = jest.fn() const nativeClick = jest.fn()
const childUpdated = jest.fn() const childUpdated = jest.fn()
class Hello extends Component { class Hello extends Component<{
count: number
}> {
data() { data() {
return { return {
count: 0 count: 0
@ -27,7 +29,7 @@ describe('attribute fallthrough', () => {
} }
} }
class Child extends Component { class Child extends Component<{}, { foo: number }> {
updated() { updated() {
childUpdated() childUpdated()
} }
@ -73,7 +75,7 @@ describe('attribute fallthrough', () => {
const nativeClick = jest.fn() const nativeClick = jest.fn()
const childUpdated = jest.fn() const childUpdated = jest.fn()
class Hello extends Component { class Hello extends Component<{ count: number }> {
data() { data() {
return { return {
count: 0 count: 0
@ -94,7 +96,7 @@ describe('attribute fallthrough', () => {
} }
} }
class Child extends Component { class Child extends Component<{}, { foo: number }> {
static options = { static options = {
props: { props: {
foo: Number foo: Number
@ -147,7 +149,7 @@ describe('attribute fallthrough', () => {
const childUpdated = jest.fn() const childUpdated = jest.fn()
const grandChildUpdated = jest.fn() const grandChildUpdated = jest.fn()
class Hello extends Component { class Hello extends Component<{ count: number }> {
data() { data() {
return { return {
count: 0 count: 0
@ -182,7 +184,7 @@ describe('attribute fallthrough', () => {
} }
} }
class GrandChild extends Component { class GrandChild extends Component<{}, { foo: number }> {
static options = { static options = {
props: { props: {
foo: Number foo: Number

View File

@ -13,17 +13,17 @@ import { ErrorTypes } from './errorHandling'
type Flatten<T> = { [K in keyof T]: T[K] } type Flatten<T> = { [K in keyof T]: T[K] }
export type RenderFunction<P = Data> = ( export type RenderFunction<P = {}> = (
props: P, props: P,
slots: Slots, slots: Slots,
attrs: Data attrs: Data
) => any ) => any
export interface ComponentClass extends Flatten<typeof InternalComponent> { export interface ComponentClass extends Flatten<typeof InternalComponent> {
new <D = Data, P = Data>(): D & P & MountedComponent<D, P> new <D = {}, P = {}>(): D & P & MountedComponent<D, P>
} }
export interface FunctionalComponent<P = Data> extends RenderFunction<P> { export interface FunctionalComponent<P = {}> extends RenderFunction<P> {
pure?: boolean pure?: boolean
props?: ComponentPropsOptions<P> props?: ComponentPropsOptions<P>
inheritAttrs?: boolean inheritAttrs?: boolean
@ -33,8 +33,7 @@ export type ComponentType = ComponentClass | FunctionalComponent
// this interface is merged with the class type // this interface is merged with the class type
// to represent a mounted component // to represent a mounted component
export interface MountedComponent<D = Data, P = Data> export interface MountedComponent<D = {}, P = {}> extends InternalComponent {
extends InternalComponent {
$vnode: MountedVNode $vnode: MountedVNode
$data: D $data: D
$props: P $props: P

View File

@ -37,11 +37,11 @@ export function updateProps(instance: MountedComponent, nextData: Data) {
const rawProps = unwrap(props) const rawProps = unwrap(props)
for (const key in rawProps) { for (const key in rawProps) {
if (!nextProps.hasOwnProperty(key)) { if (!nextProps.hasOwnProperty(key)) {
delete props[key] delete (props as any)[key]
} }
} }
for (const key in nextProps) { for (const key in nextProps) {
props[key] = nextProps[key] ;(props as any)[key] = nextProps[key]
} }
if (nextAttrs) { if (nextAttrs) {
const attrs = instance.$attrs const attrs = instance.$attrs

View File

@ -1,6 +1,7 @@
import { ChildrenFlags } from '../flags' import { ChildrenFlags } from '../flags'
import { createComponentVNode, Slots } from '../vdom' import { createComponentVNode, Slots } from '../vdom'
import { Component, ComponentType, ComponentClass } from '../component' import { Component, ComponentType, ComponentClass } from '../component'
import { unwrap } from '@vue/observer'
export interface AsyncComponentFactory { export interface AsyncComponentFactory {
(): Promise<ComponentType> (): Promise<ComponentType>
@ -92,7 +93,7 @@ export function createAsyncComponent(
} else if (this.comp) { } else if (this.comp) {
return createComponentVNode( return createComponentVNode(
this.comp, this.comp,
props, unwrap(props),
slots, slots,
ChildrenFlags.STABLE_SLOTS ChildrenFlags.STABLE_SLOTS
) )

View File

@ -4,15 +4,23 @@ import { Slots } from '../vdom'
const contextStore = observable() as Record<string | symbol, any> const contextStore = observable() as Record<string | symbol, any>
export class Provide extends Component { interface ProviderProps {
id: string | symbol
value: any
}
export class Provide extends Component<{}, ProviderProps> {
updateValue() { updateValue() {
contextStore[this.$props.id] = this.$props.value // TS doesn't allow symbol as index :/
// https://github.com/Microsoft/TypeScript/issues/24587
contextStore[this.$props.id as string] = this.$props.value
} }
created() { created() {
if (__DEV__) { if (__DEV__) {
if (contextStore.hasOwnProperty(this.$props.id)) { const { id } = this.$props
if (contextStore.hasOwnProperty(id)) {
console.warn( console.warn(
`A context provider with id ${this.$props.id} already exists.` `A context provider with id ${id.toString()} already exists.`
) )
} }
this.$watch( this.$watch(
@ -31,7 +39,7 @@ export class Provide extends Component {
beforeUpdate() { beforeUpdate() {
this.updateValue() this.updateValue()
} }
render(props: any, slots: Slots) { render(props: ProviderProps, slots: Slots) {
return slots.default && slots.default() return slots.default && slots.default()
} }
} }