# vue3 Props 源码部分解析
# 1、props 定义
export declare type Prop<T, D = T> = PropOptions<T, D> | PropType<T>; |
Prop<T, D = T> 这里的意思是指:
T 是入参类型,D 是默认值类型,如果不指定默认值的话,就用 T 的类型进行推断
# 2.PropOptions 的定义
PropOptions<T, D> 这里的入参意思也是一样的,区别在于 PropOptions 的定义
declare interface PropOptions<T = any, D = T> { | |
type?: PropType<T> | true | null; | |
required?: boolean; | |
default?: D | DefaultFactory<D> | null | undefined | object; | |
validator?(value: unknown): boolean; | |
} |
疑问:这里为什么 default 需要返回一个工厂类型
答:这里其实为了解决动态获取 props 的传递值的问题,eg:
当组件初始化时,动态的获取 props 的默认值(即 default
interface MyComponentProps { | |
myProp?: string; | |
} | |
const myPropOptions: PropOptions<string, string> = { | |
default: (props: MyComponentProps) => { | |
// Dynamic calculation of default value based on props | |
return props.myProp ? props.myProp.toUpperCase() : 'Default'; | |
}, | |
}; |
# 3.PropType 和 PropConstructor
PropType<T>
export declare type PropType<T> = PropConstructor<T> | PropConstructor<T>[]; |
PropConstructor
declare type PropConstructor<T = any> = { | |
new (...args: any[]): T & {}; | |
} | { | |
(): T; // 无参函数 | |
} | PropMethod<T>; |
这里的 PropConstructor 意思中,
new (...args: any[]): T & {};
是指创建一个新的组件时,对应的入参组件所需的构造函数类型 (即第三段代码)
// 定义组件的数据类型 | |
interface MyComponentData { | |
message: string; | |
} | |
// 定义组件的构造函数类型 | |
interface MyComponentConstructor { | |
new (): MyComponentData; | |
} | |
// 创建组件实例的函数 | |
function createMyComponent(ctor: MyComponentConstructor): MyComponentData { | |
return new ctor(); | |
} | |
// 使用组件 | |
const instance = createMyComponent(class { | |
message = 'Hello, Vue 3!'; | |
}); |
(): T;
// 无参函数 更多的是针对无需传递参数的组件,也不需要构造器,直接返回改组件的计算值即可
第三种就是接下来要介绍的 propMethods 的构造定义
# 4.propMethods
declare type PropMethod<T, TConstructor = any> = [T] extends [ | |
((...args: any) => any) | undefined | |
] ? { | |
new (): TConstructor; | |
(): T; | |
readonly prototype: TConstructor; | |
} : never; |
propMethods 解决的场景是,当不是通过显式的传值,而是通过函数计算(如 prop 传参中,default 是通过函数计算得知时,他的构造类型应该如何定义),eg:
import { defineComponent, PropType } from 'vue'; | |
// 定义一个构造函数,用于创建 Person 对象 | |
class Person { | |
constructor(public name: string) {} | |
} | |
// 定义组件的属性类型 | |
interface MyComponentProps { | |
myProp: PropType<Person>; | |
} | |
// 使用 PropMethod 来声明 myProp 的类型 | |
const MyComponent = defineComponent({ | |
props: { | |
myProp: { | |
type: PropMethod, | |
default: () => new Person('John'), // 通过普通函数计算默认值 | |
}, | |
}, | |
setup(props) { | |
console.log(props.myProp.name); // 输出: John | |
}, | |
}); |
# 5. 总结
以上就是所有关于 vue3 中,props 类型定义的 ts 源码。我个人看下来,最大的一问题是:为什么需要有构造函数的概念?gpt 给出如下例子解释 props 是如何使用的
interface ComponentProps { | |
// PropValue 是一个构造函数,它创建一个具有 name 属性的对象 | |
propValue: new () => { name: string }; | |
} | |
class MyComponent { | |
constructor(props: ComponentProps) { | |
// 创建 propValue 属性值的实例 | |
const instance = new props.propValue(); | |
console.log(instance.name); // 可以访问 name 属性 | |
} | |
} | |
// 使用 MyComponent,并传入一个具有 name 属性的构造函数 | |
const myComponent = new MyComponent({ propValue: class { name = 'John'; } }); |
上述代码,其实更多的是关于 defineComponent 的大致原理。
如下是 defineComponent 的两种使用方法
// options syntax | |
function defineComponent( | |
component: ComponentOptions | |
): ComponentConstructor | |
// function syntax (requires 3.3+) | |
function defineComponent( | |
setup: ComponentOptions['setup'], | |
extraOptions?: ComponentOptions | |
): () => any |
其中 ComponentOptions
是一个包含组件选项的接口,它描述了组件的各种配置,比如 data
、 methods
、 props
等。
ComponentConstructor
: 这个是 defineComponent
函数的返回类型。它表示一个对象的构造函数
eg:
import { defineComponent } from 'vue'; | |
// 定义一个组件 | |
const MyComponent = defineComponent({ | |
data() { | |
return { | |
message: 'Hello, Vue 3!', | |
}; | |
}, | |
methods: { | |
greet() { | |
console.log(this.message); | |
}, | |
}, | |
}); | |
// 创建组件实例 | |
const myInstance = new MyComponent(); | |
myInstance.greet(); // 输出: Hello, Vue 3! |
而 ComponentConstructor 这个其实便是 props 的核心构造函数的最外层,简而言之,相当于 defineComponent 的一切入参(ComponentOptions)便是所谓的 propValue
,亦即最初 Prop 的 PropType<T>, 其可返回其组件构造函数,亦或是无需入参只需返回组件结果,亦可返回 default 默认执行的结果。
即:Prop 是一个入参类型,本质上是一个组件的实例化与结果返回