![](/img/trans.png)
[英]Typescript/React functional component's props function - what type?
[英]JavaScript component conversion to TypeScript: What is the type of props
將 VueJS 項目從 JavaScript + Options API 遷移到 TypeScript + Composition API,我逐漸找到了大部分內容的等價物。 我正在努力解決的一件事是v-model
功能。 我找到了一篇關於使用 Composition API 實現它的好文章,作者在其中創建了一個可組合的 function ,它可以在想要實現v-model
的組件中重復使用。 我現在正在嘗試使用 TypeScript 編寫等效的 function。
這是原始的 JS 代碼:
import { computed } from 'vue'
export function useModelWrapper(props, emit, name = 'modelValue') {
return computed({
get: () => props[name],
set: (value) => emit(`update:${name}`, value)
})
}
我的 TS 實現如下所示:
import { computed, ComputedRef } from '@vue/composition-api'
export function useModelWrapper<T> (props: Record<string, unknown>, emit: (event: string, value: T) => void, name: 'modelValue') : ComputedRef {
return computed({
get: () => props[name],
set: (value) => emit(`update:${name}`, <T>value)
})
}
這編譯得很好,但 Vue 對此不太滿意。 我得到
沒有過載匹配此調用
如果我在組件中使用這個 function 會出錯。
我懷疑 TS 版本中的props
類型不正確,但我無法弄清楚我應該在那里使用什么類型。 我已經用Object
、 unknown
和any
試過了,但是它們都不允許我在 getter 中做props[name]
( any
可以,但 TS 抱怨我不應該使用any
作為props
的類型)。
我在這里做錯了什么?
這是完整的錯誤文本:
{
"resource": "../ProjectsDropdown.vue",
"owner": "_generated_diagnostic_collection_name_#6",
"code": "2769",
"severity": 8,
"message": "No overload matches this call.
Overload 1 of 3, '(options: ComponentOptionsWithoutProps<unknown, unknown, Data, {}, {}>): VueProxy<unknown, unknown, Data, {}, {}>', gave the following error.
Type '{ modelValue: PropType<Project>; }' is not assignable to type 'undefined'.
Overload 2 of 3, '(options: ComponentOptionsWithArrayProps<string, Data, Data, {}, {}, Readonly<{ [x: string]: any; }>>): VueProxy<Readonly<{ [x: string]: any; }>, Data, Data, {}, {}>', gave the following error.
Type '{ modelValue: PropType<Project>; }' is not assignable to type 'string[]'.
Object literal may only specify known properties, and 'modelValue' does not exist in type 'string[]'.
Overload 3 of 3, '(options: ComponentOptionsWithProps<ComponentPropsOptions<Data>, Data, Data, {}, {}, ({ [x: number]: string; } & { [iterator]?: IterableIterator<string> | undefined; ... 32 more ...;
toLocaleString?: string | undefined; }) | ({} & { ...; })>): VueProxy<...>', gave the following error.
Type '{ modelValue: PropType<Project>; }' is not assignable to type 'ComponentPropsOptions<Data> | undefined'.
Types of property 'modelValue' are incompatible.
Type 'PropType<Project>' is not assignable to type 'Prop<unknown, unknown> | null | undefined'.
Type 'new (...args: never[]) => Project & object' is not assignable to type 'Prop<unknown, unknown> | null | undefined'.
Type 'new (...args: never[]) => Project & object' is not assignable to type 'new (...args: string[]) => Function'.
Types of parameters 'args' and 'args' are incompatible.
Type 'string' is not assignable to type 'never'.",
"source": "Vetur",
"startLineNumber": 59,
"startColumn": 16,
"endLineNumber": 119,
"endColumn": 3
}
以下是我在組件中使用此 function 的方式:
<script lang='ts'>
export default defineComponent({
...
import { useModelWrapper } from '../usemodelWrapper'
props: {
modelValue: Object as PropType<Project>
},
setup (props, { emit }) {
return {
selectedProject: useModelWrapper<Project>(props, emit, 'modelValue')
}
})
</script>
以防萬一它可以幫助某人,結果是我在組件中使用了錯誤版本的PropType
來定義我的v-model
道具。 真正的PropType
類應該像這樣導入:
import { PropType } from '@vue/composition-api'
並不是:
import Vue, { PropType } from 'vue'
看到你自己的答案后,我覺得這可能更嚴格。
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 答案的擴展,但類型推斷是 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')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.