typescript - 打字稿,自动从对象键推断类型
问题描述
我想为可以是多个或单个项目选择的 Select 组件声明一个接口。
interface MySelect<T extends boolean> {
multi: T, // Is this a multiple items select
onChange: (item: T extends true ? string[]: string) => void // the onChange signature differs according to T
}
它有效,但我必须明确设置泛型类型 T:
const mySelect: MySelect<true> = { // Here
multi: true, // And here
onChange: (items) => {}
}
我想知道是否可以让 TS 自动从“multi”值推断 T:
const mySelect: MySelect = {
multi: true, // multi is true so T is true
onChange: (items) => {}
}
重要更新:我希望“多个”是可选的(如果键丢失或未定义,它将默认为 false)
解决方案
您已经更新了您的问题,说这multi
应该是可选的(默认为 false)。这排除了有区别的联合(下面水平线下的先前答案)。
我想我会使用两个联合在一起的接口,以及(如有必要)它们共同拥有的东西的基本接口。当您需要知道选择的类型时,您可能需要类型保护功能。
// Things all MySelects have in common (if you have anything other than `onChange`)
interface MySelectBase {
name: string;
}
// A single-select version of MySelect
interface MySingleSelect extends MySelectBase {
multi?: false;
onChange: (item: string) => void;
}
// A multi-select version of MySelect
interface MyMultiSelect extends MySelectBase {
multi: true;
onChange: (items: string[]) => void;
}
// The unified type
type MySelect = MySingleSelect | MyMultiSelect;
// Type guard function to see whether it's a single select
const isSingleSelect = (select: MySelect): select is MySingleSelect => {
return !select.multi; // !undefined and !false are both true
};
// Type guard function to see whether it's a multi select
const isMultiSelect = (select: MySelect): select is MyMultiSelect => {
return !!select.multi; // !!undefined and !!true are both true
};
创建示例:
const single: MySingleSelect = {
name: "some-single-select-field",
onChange : (item) => { console.log(item); }
};
const multi: MyMultiSelect = {
multi: true,
name: "some-multi-select-field",
onChange : (items) => { console.log(items); }
};
使用示例MySelect
(组合接口):
const useMySelect = (select: MySelect) => {
// No need for a guard on anything but `onChange`
console.log(select.name);
// `onChange` will be a union type until/unless you use a type guard
const onChange = select.onChange;
// ^^^^^^^^−−−−−−−−−− type is `((item: string) => void) | ((items: string[]) => void)`
if (isSingleSelect(select)) {
// It's a MySingleSelect
const onChange = select.onChange;
// ^^^^^^^^−−−−−−−−−− type is `(item: string) => void`
} else {
// It's a MyMultiSelect
const onChange = select.onChange;
// ^^^^^^^^−−−−−−−−−− type is `(items: string[]) => void`
}
};
这是没有要求multi
选择可选的人的原始答案:
您可以通过声明MySelect
为类型的联合来做到这一点,一个 withmulti: true
和另一个 with multi: false
:
type MySelect =
{
multi: true;
onChange: (items: string[]) => void;
}
|
{
multi: false;
onChange: (item: string) => void;
};
然后你得到:
const mySelect: MySelect = {
multi: true,
onChange: (items) => {}
// ^^^^^^^^−−−−−−−−−−− correctly inferred as (items: string[]) => void
};
这称为有区别的联合:由一个(或多个)字段的类型区分(区分)的类型的联合。
如果您有大量没有变化的其他属性,则可以使用交集将它们添加到可区分的联合中:
type MySelect =
(
{
multi: true;
onChange: (items: string[]) => void;
}
|
{
multi: false;
onChange: (item: string) => void;
}
)
&
{
the: number;
other: string;
properties: string;
};
推荐阅读
- matlab - 两个子图,一个非线性,同步问题
- r - XG-Boost: predict(...,predleaf = T) - 结果是什么意思?
- python - 如何修改“if 条件”以便同时将其应用于不同的列表?
- java - Selenium 随机点击到 Div 的
- javascript - 组件重新渲染问题 [附加片段]
- java - 从 SpringBootApplicationTest 中的应用程序上下文中排除 EurekaClient Bean
- azure-active-directory - Azure APP 注册 - 即使在授予管理员同意后,最终用户仍然会获得登录窗口,要求获得权限
- machine-learning - fit_transform 在机器学习中的影响是什么
- java - Eclipse 导入所有 Maven 项目时出错
- java - Weblogic 异常:javax.naming.NameNotFoundException:无法解析“jdbc.payment”。解决了'jdbc';其余名称“付款”