Я создаю класс в TypeScript для обработки отправки формы и ошибок сервера:
export default class Form<Model> {
private readonly original: Model
private changes: Partial<Model>
constructor(data: Model) {
this.original = data
Object.keys(this.original).forEach(key => this.initialiseData(key))
}
private initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => this.changes[key] = value
}
}
get data(): Model {
return Object.assign({}, this.original, this.changes)
}
post(url: string) {
// post logic
}
}
Это будет использоваться в моих компонентах Vue следующим образом:
import { Component, Vue } from 'vue-property-decorator'
import Form from '~/src/vform'
interface LoginForm {
email: string
password: string
}
@Component
export default class LoginView extends Vue {
form: Form<LoginForm> = new Form<LoginForm>({
email: '',
password: ''
})
async submit() {
await this.form.post('/auth/login')
}
}
Это работает, функционально, я могу заполнить форму и отправить данные на сервер. У меня проблема с реактивностью в Vue.js. Поскольку свойства не существуют в классе Form, данные не передаются в v-model, они обновляются внутри формы только после их изменения.
Это не проблема, если только я не показываю данные на экране из формы. Я могу смириться с этим пока, но мне было интересно, есть ли способ заставить Vue распознавать реактивные свойства в моем классе Form, или есть ли лучший способ добиться этой функциональности без ущерба для системы типов.






Что ж, ваша работа намного выше, чем у vuejs. Vuejs работает с реактивными данными с Object.defineProperty в установщике для повторного рендеринга, однако вы предоставляете объект, который определил свои свойства, которые не настраиваются и не смогут запускать реактивную систему vuejs.
Чтобы это работало:
export default class Form<Model> {
initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => {
this.changes[key] = value
this.onChange(key, value)
},
})
}
onChange(key, value) {}
}
import _Form from '~/src/vform'
@Component
export default class LoginView extends Vue {
form: any = {}
// Lifecycle hook
mounted() {
const vm = this
class Form extends _Form {
onChange() {
vm.$forceUpdate()
}
}
const form = new Form({
email: '',
password: ''
})
this.$set('form', form)
}
}
Обратите внимание на vm.$forceUpdate, который будет уведомлять vuejs о повторном рендеринге при изменении свойств вашей формы.