javascript - Typescript:如何正确使用泛型来正确推断函数的返回类型?
问题描述
我有以下类型
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
用预期的签名创建一个函数——</p>
// 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
推断出正确的类型,如下所示 -</p>
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
这些属性本身就是持有相同键属性的对象,那么您可以让编译器弄清楚。假设您保持这种方式,我使用了类型断言来表示,例如,“对待initialPropKey
好像它的类型是K
"。然后编译器将假定它props[initialPropKey]
的类型与props[statePropKey]
.
无论如何,现在这些函数的返回类型被推断为
P[K] | {
highlightedIndex: number;
isOpen: boolean;
selectedItem: null;
inputValue: string;
}[K]
这是有道理的,因为它defaultStateValues
在最后使用,这是一种不知道是扩展类型的具体P
类型。这可能会通过使用条件返回类型来加强,但您的示例代码没有显示需要这样做。
让我们看看它是否有效:
declare const props: AutosuggestProps;
const selectedItem = getInitialValue(props, 'selectedItem');
// const selectedItem: ItemDefaultType
在我看来是合理的。好的,希望有帮助;祝你好运!
推荐阅读
- angular - Angular 中的 HttpInterceptor 到底是什么?
- javascript - typeorm 使用现有的 sql 视图
- griddb - Go GridDb 集群未运行
- c++ - libcurl C++:检测 HTTPS 响应代码更改的长时间延迟
- python - Spacy 匹配器模式
- powershell - 获取子函数的方法
- python - 使用 spark.catalog.createTable 创建表
- javascript - Javascript无法找到函数
- laravel - 更新函数和 nWidart 模块
- angular - ABP 迁移 3.3 到 4.2 Angular 重大更改并弃用 ConfigState