handleOnChange
函数不会自动完成key
参数,并且不能为value
参数提供正确的类型。
这不符合预期。
export function MyComponent<T extends MyItem>(props: PropsWithChildren<MyComponentProps>) {
const { item, setItem } = props
function handleOnChange<K extends keyof T>(key: K) {
return function(value: T[K]) {
setItem({ ...item, [key]: value })
}
}
return <input value={item.name} onChange={e => handleOnChange('name')(e.target.value)} />
}
这确实按预期工作。
export function MyComponent<T extends MyItem>(props: PropsWithChildren<MyComponentProps>) {
const { item, setItem } = props
function handleOnChange<K extends keyof MyItem>(key: K) {
return function(value: MyItem[K]) {
setItem({ ...item, [key]: value })
}
}
return <input value={item.name} onChange={e => handleOnChange('name')(e.target.value)} />
}
您知道为什么在这种情况下泛型会导致问题吗?
答案 0 :(得分:0)
您是否尝试过使用K keyof T
而不是K extends keyof T
?
答案 1 :(得分:0)
对于问题的IntelliSense部分,看起来当keyof A
时检查keyof B
时,完成列表只是不包括B extends A
。如果可以,那会很好,但事实并非如此。 suggested是这样的更改。如果您希望看到这种情况发生,那么您可能想看一下Github上的问题,或者如果您认为它既引人注目又与现有内容不同,请描述您的用例。
目前,解决方法可能是将约束更改为K extends keyof T | keyof MyItem
。由于keyof T
已经必须包含keyof MyItem
,因此,keyof MyItem
的附加并集不会改变什么类型的K
有效规范。但这确实会带回您期望的IntelliSense自动完成列表。
对于问题的“ value
参数的正确类型”部分,我想我需要详细说明您的意思。但请注意:如果T extends MyItem
,则T["name"]
的类型可能比MyItem["name"]
的更窄。想象一下:
interface MyItem {
name: string;
}
export function MyComponent<T extends MyItem>() {
function handleOnChange<K extends keyof T | keyof MyItem>(key: K) {
return function (value: T[K]) { }
}
handleOnChange("name")("Fred"); // wait a minute
}
TypeScript允许您使用任何handleOnChange("name")(xxx)
作为string
来调用xxx
,即使这样做并不安全。观察:
interface MyItemNamedBob extends MyItem {
name: "Bob";
}
MyComponent<MyItemNamedBob>(); // ?
类型为MyItemNamedBob
的值在类型级别具有文字字符串"Bob"
作为name
。无法将其更改为"Fred"
。对于扩展了handleOnChange("name")
的通用T
来说,MyItem
根本无法安全地接受任何内容。在实践中,这可能并不重要,但是您应该小心,因为编译器并不总是如此。
好的,希望能有所帮助;祝你好运!