types: ensure props are readonly
This commit is contained in:
		
							parent
							
								
									a5f962ab8e
								
							
						
					
					
						commit
						08bf9976ae
					
				@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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>>
 | 
			
		||||
 | 
			
		||||
@ -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 {
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user