]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
types: ensure props are readonly
authorEvan You <yyx990803@gmail.com>
Sat, 9 Nov 2019 23:40:25 +0000 (18:40 -0500)
committerEvan You <yyx990803@gmail.com>
Sat, 9 Nov 2019 23:40:25 +0000 (18:40 -0500)
packages/runtime-core/src/apiCreateComponent.ts
packages/runtime-core/src/apiOptions.ts
packages/runtime-core/src/componentProps.ts
test-dts/createComponent.test-d.tsx

index f4ab9bd3792260b5eefa9b6b2a1eada7cfaf0e7f..bd23f6785b437ca7604304cb72030bd8fb006b53 100644 (file)
@@ -14,7 +14,10 @@ import { VNodeProps } from './vnode'
 // overload 1: direct setup function
 // (uses user defined props interface)
 export function createComponent<Props, RawBindings = object>(
-  setup: (props: Props, ctx: SetupContext) => RawBindings | RenderFunction
+  setup: (
+    props: Readonly<Props>,
+    ctx: SetupContext
+  ) => RawBindings | RenderFunction
 ): {
   new (): ComponentPublicInstance<
     Props,
index 829dfdcc7625819530f24f2be741acf16d2f3478..d6068d8dac75684c0f8c74dae90a3a66b8e0adde 100644 (file)
@@ -83,7 +83,7 @@ export type ComponentOptionsWithoutProps<
   M extends MethodOptions = {}
 > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
   props?: undefined
-} & ThisType<ComponentPublicInstance<{}, RawBindings, D, C, M, Props>>
+} & ThisType<ComponentPublicInstance<{}, RawBindings, D, C, M, Readonly<Props>>>
 
 export type ComponentOptionsWithArrayProps<
   PropNames extends string = string,
@@ -91,7 +91,7 @@ export type ComponentOptionsWithArrayProps<
   D = {},
   C extends ComputedOptions = {},
   M extends MethodOptions = {},
-  Props = { [key in PropNames]?: any }
+  Props = Readonly<{ [key in PropNames]?: any }>
 > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
   props: PropNames[]
 } & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
@@ -102,7 +102,7 @@ export type ComponentOptionsWithObjectProps<
   D = {},
   C extends ComputedOptions = {},
   M extends MethodOptions = {},
-  Props = ExtractPropTypes<PropsOptions>
+  Props = Readonly<ExtractPropTypes<PropsOptions>>
 > = ComponentOptionsBase<Props, RawBindings, D, C, M> & {
   props: PropsOptions
 } & ThisType<ComponentPublicInstance<Props, RawBindings, D, C, M>>
index 41ce30963b3222703f64bcf85a8bf09c5c4ce35b..ead0784db603c5c4cc39a03c31cf6f26310fec89 100644 (file)
@@ -65,14 +65,8 @@ export type ExtractPropTypes<
   O,
   MakeDefaultRequired extends boolean = true
 > = O extends object
-  ? {
-      readonly [K in RequiredKeys<O, MakeDefaultRequired>]: InferPropType<O[K]>
-    } &
-      {
-        readonly [K in OptionalKeys<O, MakeDefaultRequired>]?: InferPropType<
-          O[K]
-        >
-      }
+  ? { [K in RequiredKeys<O, MakeDefaultRequired>]: InferPropType<O[K]> } &
+      { [K in OptionalKeys<O, MakeDefaultRequired>]?: InferPropType<O[K]> }
   : { [K in string]: any }
 
 const enum BooleanFlags {
index 7d563207d2aa35314ecb0405ad3db879bbb9eb90..ce15c70428c92391a2a7d313ff2e1aabc73cd050 100644 (file)
@@ -71,6 +71,9 @@ describe('with object props', () => {
       expectType<ExpectedProps['ccc']>(props.ccc)
       expectType<ExpectedProps['ddd']>(props.ddd)
 
+      // props should be readonly
+      expectError((props.a = 1))
+
       // should also expose declared props on `this`
       expectType<ExpectedProps['a']>(this.a)
       expectType<ExpectedProps['b']>(this.b)
@@ -80,10 +83,16 @@ describe('with object props', () => {
       expectType<ExpectedProps['ccc']>(this.ccc)
       expectType<ExpectedProps['ddd']>(this.ddd)
 
+      // props on `this` should be readonly
+      expectError((this.a = 1))
+
       // assert setup context unwrapping
       expectType<number>(this.c)
       expectType<string>(this.d.e)
 
+      // setup context properties should be mutable
+      this.c = 2
+
       return null
     }
   })
@@ -126,6 +135,9 @@ describe('type inference w/ optional props declaration', () => {
     },
     render() {
       expectType<string>(this.$props.msg)
+      // props should be readonly
+      expectError((this.$props.msg = 'foo'))
+      // should not expose on `this`
       expectError(this.msg)
       expectType<number>(this.a)
       return null
@@ -148,14 +160,18 @@ describe('type inference w/ array props declaration', () => {
   createComponent({
     props: ['a', 'b'],
     setup(props) {
-      props.a
-      props.b
+      // props should be readonly
+      expectError((props.a = 1))
+      expectType<any>(props.a)
+      expectType<any>(props.b)
       return {
         c: 1
       }
     },
     render() {
-      expectType<{ a?: any; b?: any }>(this.$props)
+      expectType<any>(this.$props.a)
+      expectType<any>(this.$props.b)
+      expectError((this.$props.a = 1))
       expectType<any>(this.a)
       expectType<any>(this.b)
       expectType<number>(this.c)