我正在学习Typescript,并且有一个类似于下面的自定义React钩子:
import { useEffect, useState } from 'react';
type TypeOne = {
one: string;
};
type TypeTwo = {
two: number;
};
type TypeThree = {
three: {
some: string;
};
}
type AnyPropertyWithString = {
[index: string]: string | AnyPropertyWithString;
};
export function getContent(condition: string): Promise<AnyPropertyWithString> {
return Promise.resolve({ one: 'content' });
}
export default function useContent<T extends AnyPropertyWithString>(
initial: T,
condition: string
): T {
const [content, setContent] = useState<T>(initial);
useEffect(() => {
async function fetchData() {
const data = await getContent(condition);
setContent(data);
}
fetchData();
}, [condition]);
return content;
}
我的意图是最初提供不同类型的数据给这个钩子,并将其保存在一个状态中。然后在某些条件下获取新的数据并替换状态。我想将提供给钩子的类型限制为AnyPropertyWithString
。我想使用泛型,因为我将提供的类型可能有不同的属性和多个级别。返回类型应该与泛型相同。
我希望这样使用它:
const one: TypeOne = { one: 'content' };
const two: TypeTwo = { two: 2 };
const three: TypeThree = { three: { some: '3' } }
const firstResult = useContent(one, 'condition'); // ok
const secondResult = useContent(two, 'condition'); // expected TS error
const thirdResult = useContent(three, 'condition'); // ok
但是,当我尝试setContent(data)
时,我有一个错误:
Argument of type 'AnyPropertyWithString' is not assignable to parameter of type 'SetStateAction<T>'.
Type 'AnyPropertyWithString' is not assignable to type 'T'.
'AnyPropertyWithString' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'AnyPropertyWithString'.
我不想将它转换为T
,因为我已经读到这是一个不好的做法。
我怀疑问题是getContent
返回的数据类型无法有效匹配,但我认为泛型约束会将T缩小到AnyPropertyWithString
(由getContent
返回)。我尝试了useState<T | AnyPropertyWithString>
,但返回类型有问题。我还尝试了extends
的不同组合,但都不起作用。
请您解释一下为什么我会出现此错误,以及如果可能的话,我如何解决它?
我真的很感激你能提供的任何帮助。
1条答案
按热度按时间vnzz0bqm1#
getContent
如何知道T
是什么,然后以T
的格式返回数据?执行此操作时:
那么
useContent
中的T
类型是{ foo: string }
,它是AnyPropertyWithString
的子类型。getContent
返回与T
完全不同的子类型。因此,如果运行此代码,则初始值会将
T
设置为{ foo: string }
,然后效果会运行,并且您会将{ one: string }
保存为state,这是一个不兼容的类型。那么您的代码将执行以下操作:
以下是此错误的含义:
'AnyPropertyWithString'可指派给型别'T'的条件约束,但'T'可以用条件约束'AnyPropertyWithString'的不同子类型执行严修化。
目前还不清楚
getContent
将如何工作,但它需要知道在运行时返回哪种数据格式,而您没有向它传递任何可以让它弄清楚这一点的信息。因此,如果你弄清楚
getContent
将如何返回与挂钩的initial
参数类型相同的类型,那么答案将开始显现。