- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这段带有泛型的代码片段工作得很好( Link to Simple and Working Code )
const state: Record<string, any> = {
isPending: false,
results: ['a', 'b', 'c']
}
const useValue = <T extends {}>(name: string): [T, Function] => {
const value: T = state[name]
const setValue: Function = (value: T): void => {
state[name] = value
}
return [value, setValue]
}
const [isPending, setIsPending] = useValue<boolean>('isPending')
const [results, setResults] = useValue<string[]>('results')
在这里我可以确定 isPending
是一个 bool 值并且 setIsPending
接收一个 bool 值作为参数。同样适用于 results
和 setResults
作为字符串数组。
然后我用另一种方法包装代码 useStore
( Link to Extended Broken Code )
interface UseStore {
state: Record<string, any>
useValue: Function
}
const state: Record<string, any> = {
isPending: false,
results: ['a', 'b', 'c']
}
const useStore = (): UseStore => {
const useValue = <T extends {}>(name: string): [T, Function] => {
const value: T = state[name]
const setValue: Function = (value: T): void => {
state[name] = value
}
return [value, setValue]
}
return { state, useValue }
}
const { useValue } = useStore()
const [isPending, setIsPending] = useValue<boolean>('isPending')
const [results, setResults] = useValue<string[]>('results')
最后两行给我 typescript 错误:Untyped function calls may not accept type arguments.
我怀疑 useStore
接口(interface)有问题,但由于它的动态特性,我想不出更好的解决方案。
如何在使用泛型类型时消除错误以获得正确的类型提示和代码完成?
最佳答案
由于useValue
的类型是Function
,所以传递泛型参数是没有意义的。他们对谁有利?运行时没有得到它们,它们在编译时被删除。编译器无法使用它们,因为 Function
只是一个未类型化的函数,因此没有任何好处。传递类型参数是无用的,并且可以说是一个错误(即用户不期望这是 Function
并且认为它们有一些效果而传递了类型参数)。
删除类型参数并放弃以任何方式键入的假装:
const { useValue } = useStore()
const [isPending, setIsPending] = useValue('isPending')
const [results, setResults] = useValue('results')
更有趣的问题是你为什么要写这样的代码,因为有一种方法可以完全键入这段代码中的所有内容:
const state = {
isPending: false,
results: ['a', 'b', 'c']
}
type State = typeof state;
const useStore = () => {
const useValue = <K extends keyof State>(name: K) => {
const value = state[name]
const setValue = (value: State[K]): void => {
state[name] = value
}
return [value, setValue] as const
}
return { state, useValue }
}
type UseStore = ReturnType<typeof useStore>;
const { useValue } = useStore()
const [isPending, setIsPending] = useValue('isPending')
const [results, setResults] = useValue('results')
上面的版本是完全类型安全的,不需要任何重复的名称或类型(您当然可以将其拆分为多个文件,但根据您的要求,可能需要进行一些重复)。如果这不适用于您的情况,我很想知道原因。
编辑
如果您只想让类型在最后几行运行并在那里有一些类型安全性,您只需要使用泛型指定函数的签名:
interface UseStore {
state: Record<string, any>
useValue: <T,>(name: string) => [T, (value: T)=> void]
}
const state: Record<string, any> = {
isPending: false,
results: ['a', 'b', 'c']
}
const useStore = (): UseStore => {
const useValue = <T,>(name: string): [T, (value: T)=> void] => {
const value: T = state[name]
const setValue = (value: T): void => {
state[name] = value
}
return [value, setValue]
}
return { state, useValue }
}
const { useValue } = useStore()
const [isPending, setIsPending] = useValue<boolean>('isPending')
const [results, setResults] = useValue<string[]>('results')
编辑 - 接口(interface)实现的开放式
您可以将State
定义为接口(interface),因为接口(interface)是开放式的,您可以在需要时添加成员。好处是如果其他人定义了一个名称相同但类型不同的属性,你会得到一个错误
界面状态{
}
// Don't know what is in here, empty object for starters
const state : State = {
} as State
const useStore = () => {
const useValue = <K extends keyof State>(name: K) => {
const value = state[name]
const setValue = (value: State[K]): void => {
state[name] = value
}
return [value, setValue] as const
}
return { state, useValue }
}
type UseStore = ReturnType<typeof useStore>;
const { useValue } = useStore()
interface State { isPending: boolean }
state.isPending = false; // no guarantee people actually intialize, maybe initial value can be passed to useValue ?
const [isPending, setIsPending] = useValue('isPending')
interface State { results: string[] }
state.results = ['a', 'b', 'c'];
const [results, setResults] = useValue('results')
interface State { results: number[] } // some else wants to use results for something else, err
const [results2, setResults2] = useValue('results')
关于javascript - typescript 泛型包装器 : Untyped function calls may not accept type arguments,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55790728/
我是一名优秀的程序员,十分优秀!