开发者问题收集

JavaScript 组件转换为 TypeScript:props 的类型是什么

2021-10-21
874

从JavaScript + Options API迁移Vuejs项目到打字稿 + Coption API,我逐渐发现了大多数内容的等效物。我正在努力的一件事是 v-Model 功能。我找到了一个 使用构图API ,其中作者创建了一个可复合功能,可以在要实现 v-model 的组件中重复使用。我现在正在尝试使用Typescript编写等效函数。

这是原始JS代码:

365698686

我的TS实现看起来像这样:< /p> 163269010

此编译罚款,但VUE对此并不满意。我得到

066492575

如果我在组件中使用此功能。

我的怀疑是 props props 的类型TS版本不正确,但是我无法弄清楚在那里应该使用哪种类型。我已经使用 对象未知任何 尝试过,但是它们都不允许我做 props [name] 在getter中( 任何 都这样做,但TS抱怨我不应该使用 任何 作为 props 的类型)。

< P>我在这里做错了什么?

编辑

这是完整的错误文本:

711750269

编辑2

这是我在组件中使用此功能的方式:

08888858623
3个回答

看到您自己的回答后,我觉得这可能更加严格。

import { computed, WritableComputedRef } from '@vue/composition-api'

export function useModelWrapper<TProps, TKey extends keyof TProps> (
  props: TProps,
  emit: (event: string, value: TProps[TKey]) => void,
  name: TKey = 'modelValue' as TKey
) : WritableComputedRef<TProps[TKey]> {
  return computed<TProps[TKey]>({
    get: () => props[name],
    set: (value: TProps[TKey]) => emit('input', value)
  })
}

我还没有专门用 Vue 测试过,但该函数应该限制您可以将哪个键作为第三个参数传递,并根据传递的 name 而不是所有 props 值的并集正确推断返回类型。

emeraldsanto
2021-10-22

以防万一它能帮助到其他人,事实证明我在组件中使用了错误版本的 PropType 来定义我的 v-model prop。真正的 PropType 类应该像这样导入:

import { PropType } from '@vue/composition-api'

而不是:

import Vue, { PropType } from 'vue'

编辑

如果它能帮助到任何人,下面是我最终使用 Composition API 和 TypeScript 实现强类型 v-model 的方法:

import { computed, WritableComputedRef } from '@vue/composition-api'

export interface IIndexable<T> { [key: string]: T }

export function useModelWrapper<T> (props: IIndexable<T>, emit: (event: string, value: T) => void, name = 'modelValue') : WritableComputedRef<T> {
  return computed<T>({
    get: () => props[name] as T,
    set: (value: T) => emit('input', value as T)
  })
}

然后,您可以像这样将其导入任何组件:

export default defineComponent({
  name: 'ProjectsDropdown',
  props: {
    value: Object as PropType<Project>
  },
  setup (props, { emit }) {
    const selectedProject = useModelWrapper<Project>(props, emit, 'value')

    return { selectedProject }
  }
}

并将其绑定到您想要在组件模板中绑定的任何内容。

请注意,这在 Vue 2.x 中有效。对于 Vue 3,您需要将 value prop 的名称更改为 modelValue ,并将上述代码中的 emit('input', value as T) 更改为 emit('update:modelValue', value)

编辑 2

请参阅下面 @emeraldsanto 的回答。它提供了更好的实现。

dotNET
2021-10-21

这是 @emeraldsanto 答案的扩展,但类型推断是 Vue 3 组件发出的字符串

export function useModelWrapper<TProps extends Record<string, unknown> | { modelValue: unknown },
                                TKey extends keyof TProps & string = 'modelValue',
                                TEmit extends (event: `update:${TKey}`, value: TProps[TKey]) => void = (event: `update:${TKey}`, value: TProps[TKey]) => void > (
  props: TProps,
  emit: TEmit,
  name: TKey = 'modelValue' as TKey
) : WritableComputedRef<TProps[TKey]> {
  return computed<TProps[TKey]>({
    get: () => props[name],
    set: (value: TProps[TKey]) => emit(`update:${name}` as `update:${TKey}`, value)
  })
}

类似使用

const props = defineProps<{
  modelValue: string
  foo?: number
}> ()

const emit = defineEmits<{
  (e: 'update:modelValue', id: string): void
  (e: 'update:foo', value: number | undefined): void
}> ()
const value = useModelWrapper(props, emit)
const fooValue = useModelWrapper(props, emit, 'foo')
Brent
2022-03-14