在React中,您可以定义prop是一个对象,然后定义该对象属性的类型,即形状。在Vue中,似乎唯一可以检查对象是否具有某种形状的方法是使用验证器函数。这是目前推荐的策略吗?我确定还有其他库可以用来处理验证,但它似乎是Vue应该能够处理的东西。
答案 0 :(得分:1)
你绝对应该使用TypeScript。您期望的是"类型注释",您将快速了解TypeScript Quick start tutorial。
Vue.js开箱即用,提供TypeScript支持。见https://vuejs.org/v2/guide/typescript.html
答案 1 :(得分:0)
仅使用TypeScript的解决方案的问题在于,它仅在编译时检查类型,并且仅限于类型检查。如果您要传递动态对象或需要其他数据约束,那么这对运行时不会有帮助。
我最近发现了一个用于运行时验证的库,但是它不适合与Vue 2.x或Babel编译器一起使用,因为它使用JavaScript保留字作为函数名。因此,我分叉了该项目,重构了代码以同时支持TypeScript和JavaScript,并特别添加了一个asSuccess()
函数来支持VueJS对象属性的验证。
因此,如果您有TypeScript接口,例如...
interface Pet {
name: string;
species: string;
age?: number;
isCute?: boolean;
}
您可以使用JavaScript或TypeScript代码作为...来验证Pet属性...
import { tObject, tString, tNumber, tBoolean, optional } from 'runtime-validator'
// VueJs component
export default {
name: 'MyPet',
props: {
pet: {
type: Object,
required: true,
validator: tObject({
name: tString(),
species: tString(),
age: optional(tNumber()),
isCute: optional(tBoolean())
}).asSuccess
}
},
...
}
tObject()
将接受具有定义的其他字段的对象。如果您需要禁止其他字段,请使用tObjectStrict()
。
您还可以添加值约束...
export default {
name: 'MyPet',
props: {
pet: {
type: Object,
required: true,
validator: tObject({
name: tString(),
species: oneOf("cat", "dog", "bird"),
age: optional(range(0, 150)),
isCute: optional(tBoolean())
}).asSuccess
}
},
...
}
它比属性具有更广泛的应用,因为它还可以用于单元测试,vuex动作和变异,服务器端有效载荷等中的数据验证。
完整文档在这里...
答案 2 :(得分:-1)
我要躲开@ Clorichel的回答,因为TypeScript正在为我创造奇迹。这是一个迟到的答案,但我一直需要和你一样的东西:对象模式验证,而不仅仅是" is this prop a string or number?"。 TypeScript提供了interface的用法,它将对象的形状以合同方式绑定到该类型(接口)。所以,如果我有
interface GreetingSchema {
message: string;
}
执行let myGreeting = <GreetingSchema>{ message: 1234 }
会抛出错误
Type '{ message: number; }' cannot be converted to type 'GreetingSchema'.
Types of property 'message' are incompatible.
Type 'number' is not comparable to type 'string'.
通过将其与Vue集成,可以进一步扩展它,您可以在编译期间利用接口对从父项传递给子项的组件道具执行对象模式验证。例如,一个子Greeting
组件(Greeting.vue)可以与将传递给它的props的对象模式耦合(我使用嵌套模式来调整事物):
<template>
<div>
{{message}}{{
speaker
? ` from ${speaker.firstName}${
speaker.lastName ? ` ${speaker.lastName}` : ''
}
: ''
}}
</div>
</template>
<script lang="ts">
export default {
name: 'greeting',
props: ['message', 'speaker'],
}
interface SpeakerSchema { // this will be a nested schema
firstName: string;
lastName?: string; // last name of speaker is optional
}
export interface GreetingSchema {
message: string;
speaker?: SpeakerSchema; // speaker is optional
}
</script>
然后,您可以将Greeting
组件及其对应的GreetingSchema
导入父级,以确保父级将其greetingData
传递给子级Greeting
时{ {1}},v-bind
将受greetingData
GreetingSchema
令人敬畏的是,即使在<template>
<div>
This greeting is being displayed from the parent:
<greeting v-bind="greetingData" />
</div>
</template>
<script lang="ts">
import Greeting, {GreetingSchema} from './Greeting' // path to Greeting.vue
export default {
name: 'parent',
components: {Greeting},
data () {
return {
greetingData: <GreetingSchema>{
message: 'hi there',
speaker: {
firstName: 'myFirstName',
lastName: 1234 // error because it's not a string
},
}
}
},
}
</script>
文件中,错误也可以直接在文本编辑器中显示正确的扩展名。我正在使用Visual Studio Code,它具有开箱即用的TypeScript支持,并使用vetur extension。什么甚至是令人敬畏的是TypeScript's home page features a presentation in which TypeScript is used with Vue's single file components!