我有以下几种
type ItemDefaultType = object | null | string
interface ItemToString<Item = ItemDefaultType> {
(item: ItemDefaultType): string;
}
interface AutosuggestState<Item = ItemDefaultType> {
highlightedIndex: number | null
inputValue: string | null
isOpen: boolean
selectedItem: Item
}
interface AutosuggestProps<Item = ItemDefaultType> extends AutosuggestState<Item> {
itemToString?: ItemToString<Item>;
initialSelectedItem?: Item;
initialInputValue?: string;
initialHighlightedIndex?: number | null;
initialIsOpen?: boolean;
defaultHighlightedIndex?: number | null;
defaultIsOpen?: boolean;
id?: string;
inputId?: string;
labelId?: string;
menuId?: string;
itemCount?: number
}
我想使用预期的签名制作一个
getInitialValue
函数–// this has to be done correctly using generics, not been able to do it, read on…
(
props: Props extends AutosuggestProps,
stateKey: StateKey extends keyof AutosuggestState
) => AutosuggestState[StateKey] // return the correct type of AutosuggestState property based on which stateKey was passed
getInitialValue
的行为如下所示// javascript version
const defaultStateValues = {
highlightedIndex: -1,
isOpen: false,
selectedItem: null,
inputValue: ''
}
function getDefaultValue(props, statePropKey) {
const defaultPropKey = `default${capitalizeString(statePropKey)}`
if (defaultPropKey in props) {
return props[defaultPropKey]
}
return defaultStateValues[statePropKey]
}
function getInitialValue(props, statePropKey) {
if (statePropKey in props) {
return props[statePropKey]
}
const initialPropKey = `initial${capitalizeString(statePropKey)}`
if (initialPropKey in props) {
return props[initialPropKey]
}
return getDefaultValue(props, statePropKey)
}
我发现很难同时编写
getInitialValue
和getDefaultValue
的类型,以致getInitialValue
正确地推断出正确的类型,如下所示–const selectedItem = getInitialValue(props, 'selectedItem') // selectedItem variable should correctly be inferred as **object | null | string** since that's what its type is in **AutosuggestState** interface
有人可以帮我写类型吗?
最佳答案
这是一种可能的输入方式,它可能适合您的用例,也可能不适合您的用例:
function getDefaultValue<P extends AutosuggestProps, K extends keyof AutosuggestState>(
props: P,
statePropKey: K) {
const defaultPropKey = `default${capitalizeString(statePropKey)}`
if (defaultPropKey in props) {
return props[defaultPropKey as K] // assert here
}
return defaultStateValues[statePropKey]
}
function getInitialValue<P extends AutosuggestProps, K extends keyof AutosuggestState>(
props: P, statePropKey: K) {
if (statePropKey in props) {
return props[statePropKey]
}
const initialPropKey = `initial${capitalizeString(statePropKey)}`
if (initialPropKey in props) {
return props[initialPropKey as K] // assert here
}
return getDefaultValue(props, statePropKey)
}
我真正要做的就是使函数在您在伪代码中提到的类型的
P
和K
中通用。您需要做出的一项决定是使用
defaultPropKey
和initialPropKey
时该怎么做。编译器无法验证是否在属性名称前加上"default"
或"initial"
(如果存在)会选择另一个相同类型的属性。编译器无法理解类型级别的字符串连接(在Github中这样做的建议似乎是microsoft/TypeScript#12754)。如果可以重构接口,以便将默认值和初始值存储在名为default
和initial
的属性中,它们本身就是持有相同键的属性的对象,那么可以使编译器弄清楚。假设您保持这种方式,我使用了type assertion来表示“例如,处理initialPropKey
就像它是K
类型一样”。然后,编译器将假定props[initialPropKey]
与props[statePropKey]
具有相同的类型。无论如何,现在将这些函数的返回类型推断为
P[K] | {
highlightedIndex: number;
isOpen: boolean;
selectedItem: null;
inputValue: string;
}[K]
这很有意义,因为它在末尾使用
defaultStateValues
,这是一种具体的类型,不知道是扩展的P
类型。通过使用conditional返回类型可以加强这一点,但是您的示例代码并未显示出这种需要。让我们看看它是否有效:
declare const props: AutosuggestProps;
const selectedItem = getInitialValue(props, 'selectedItem');
// const selectedItem: ItemDefaultType
在我看来合理。好的,希望能有所帮助;祝好运!
Link to code
关于javascript - typescript :如何正确使用泛型正确推断函数的返回类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58643699/