为什么TypeScript在将对象文字指定给扩展对象文字的泛型类型时会抱怨?
我不明白为什么TypeScript编译器会抱怨这段代码:为什么TypeScript在将对象文字指定给扩展对象文字的泛型类型时会抱怨?,typescript,typescript-typings,Typescript,Typescript Typings,我不明白为什么TypeScript编译器会抱怨这段代码: import { useState, useEffect } from 'react'; function useSomething<T extends { [key: string]: any }>(): T { const [state, setState] = useState<T>({}); // Argument of type '{}' is not assignable to paramete
import { useState, useEffect } from 'react';
function useSomething<T extends { [key: string]: any }>(): T {
const [state, setState] = useState<T>({}); // Argument of type '{}' is not assignable to parameter of type 'T | (() => T)'.
useEffect(() => {
setState({ hello: 'world' });
});
return state;
}
关于代码的一些注释:
- 我希望
始终是一个对象T
,因此任何人都不能执行{}
useComplexState
- 理想情况下,
不应该是必需的,所以如果我使用T
我应该在里面有一个通用对象useComplexState()
记录
- 我希望
状态的默认值为
{}
useState({}ast)中添加ast
修复了每个问题。在useState({}ast)中添加ast
修复了每个问题。因为您可以调用useSomething()
但是{code}
不能分配给{foo:number}
。(请注意,T扩展X
并不意味着所有的X
都可以分配给T
。相反)为什么useSomething()
是通用的?你打算怎么称呼它呢?谢谢你的评论,但是我还是不完全理解这个问题。我知道{foo:number}
不是{}
,但我假设如果我用一组严格的属性定义一个接口或一个类型,情况就是这样,但在这里,我理解的是:“只要它是一个具有字符串键的对象,并且任何东西都是值,就可以了”然而,为什么这行可以工作<代码>常量t:{[key:string]:any}={}
@jcalz用一个更好的用法示例更新了这个问题。说T
is{[k:string]:any}
和T扩展{[k:string]:any}
之间有区别。后者意味着T
可能是一种限制性更强的类型。因此,如果我调用useSomething()
我是说T
肯定有一个foo
类型的属性number
。行const t:{[k:string]:any}={}
工作,因为t
的类型是{[k:string]:any}
。我不知道如何更清楚地解释这一点:A扩展了B
并不意味着可以将B
类型的值分配给A
类型的变量。相反,因为您可以调用useSomething()
,但是{}
不能分配给{foo:number}
。(请注意,T扩展X
并不意味着所有的X
都可以分配给T
。相反)为什么useSomething()
是通用的?你打算怎么称呼它呢?谢谢你的评论,但是我还是不完全理解这个问题。我知道{foo:number}
不是{}
,但我假设如果我用一组严格的属性定义一个接口或一个类型,情况就是这样,但在这里,我理解的是:“只要它是一个具有字符串键的对象,并且任何东西都是值,就可以了”然而,为什么这行可以工作<代码>常量t:{[key:string]:any}={}
@jcalz用一个更好的用法示例更新了这个问题。说T
is{[k:string]:any}
和T扩展{[k:string]:any}
之间有区别。后者意味着T
可能是一种限制性更强的类型。因此,如果我调用useSomething()
我是说T
肯定有一个foo
类型的属性number
。行const t:{[k:string]:any}={}
工作,因为t
的类型是{[k:string]:any}
。我不知道如何更清楚地解释这一点:A扩展了B
并不意味着可以将B
类型的值分配给A
类型的变量。反过来说如果你没事的话可能会对编译器撒谎{}
几乎肯定不是T
类型的值。考虑到您的实现,我最多只能说您应该使用Partial
而不是T
。从技术上讲,您是对的,它应该是useState({})
,因此,如果我将代码链接为单独的答案并附上解释,您会接受吗?或者你想自己修改这个答案?继续吧,我会接受的。这是我能为你做的最起码的事。是的,如果你没事的话,可能会对编译器撒谎{}
几乎肯定不是T
类型的值。考虑到您的实现,我最多只能说您应该使用Partial
而不是T
。从技术上讲,您是对的,它应该是useState({})
,因此,如果我将代码链接为单独的答案并附上解释,您会接受吗?或者你想自己修改这个答案?继续吧,我会接受的。这是我能为你做的最起码的事。
import { useState } from 'react';
function useComplexState<T extends Record<string, any>>() {
const [state, setState] = useState<T>({});
const setter = (key: keyof T, value: any) => {
setState((state) => ({ ...state, [key]: value }));
return state;
};
const getter = (key: keyof T) => {
return state[key];
}
return { set: setter, get: getter };
}
interface Person {
firstName: string;
lastName: string;
}
const personState = useComplexState<Person>();
personState.get('firstName');
personState.set('lastName', 'Smith');