如果多次传递另一个参数,则Typescript需要参数
我正在尝试做一个分布式联合类型,其中传递一个键,需要其他键如果多次传递另一个参数,则Typescript需要参数,typescript,Typescript,我正在尝试做一个分布式联合类型,其中传递一个键,需要其他键 接口基本参数{ 标题:字符串 } 接口函数{ 启用寻呼机:true 限制:数目 计数:数字 } 类型FuncArgs=(FuncPagerArgs和BaseArgs)| BaseArgs; 函数func(参数:FuncArgs){ 如果(args中的“enablePager”){ 寻呼机({limit:args.limit,count:args.count}); } } 接口页面{ 限制:数目 计数:数字 } 函数寻呼机(args:Pa
接口基本参数{
标题:字符串
}
接口函数{
启用寻呼机:true
限制:数目
计数:数字
}
类型FuncArgs=(FuncPagerArgs和BaseArgs)| BaseArgs;
函数func(参数:FuncArgs){
如果(args中的“enablePager”){
寻呼机({limit:args.limit,count:args.count});
}
}
接口页面{
限制:数目
计数:数字
}
函数寻呼机(args:PagerArgs){
}
func({
标题:“某物”,
启用寻呼机:true
})
对我来说,该代码不应该通过验证,因为我在传递enablePager时调用了
func
,但当enablePager
为true时,我没有通过limit
或count
这两个都是必需的。在我的现实世界示例中,我尝试对3或4个不同的特性布尔值执行此模式,每个特性布尔值都将改变契约以需要更多字段。不幸的是,我甚至不能使用第一个布尔特性,更不用说多个了。我们在这里看到的问题与联合元素之间没有适当的区别有关。我们在两个成员之间有重叠(funcpagerags&BaseArgs)| BaseArgs
,重叠相等BaseArgs
。非常重要的是:
在比较函数参数的类型时,如果源参数可分配给目标参数,则分配成功,反之亦然
这意味着什么-如果我们的类型可以分配给想要的类型,或者想要的类型可以分配给我们的参数类型,那么您可以传递它。考虑测试:
type ArgType = {
title: "something",
enablePager: true
}
type IsAssignable = ArgType extends FuncArgs ? true : false; // true, can be passed
所以您要传递的类型是可分配给想要的类型的,那么TS允许传递它。不要问我为什么,这是设计决策,你可以把它理解为一种妥协,更严格会阻止许多想要的行为,至少我在上面链接的TS文档中已经说明了这一点。可以肯定的是,现在代码中存在的问题将使我们成为运行时错误
为了解决这个问题,我们需要创建一个没有重叠的适当的有歧视的联盟
interface BaseArgs {
title: string
}
interface OnlyTitle extends BaseArgs {
kind: 'TITLE'
}
interface FuncPagerArgs extends BaseArgs {
kind: 'PAGER'
enablePager: true
limit: number
count: number
}
type FuncArgs = OnlyTitle | FuncPagerArgs;
function func(args: FuncArgs) {
if (args.kind === 'PAGER') {
pager({ limit: args.limit, count: args.count });
}
}
interface PagerArgs {
limit: number
count: number
}
function pager(args: PagerArgs) {
}
func({
kind: "TITLE",
enablePager: true
}) // error
func({
kind: "TITLE",
title: 'title'
}) // correct
我所做的是以kind
属性的形式,它将允许在适当的成员上不存在任何重叠。这意味着现在您只能使用或一个或另一个变体,类型永远不会重叠
在评论之后编辑
作者在评论中表示,他需要将所有选项组合在一起,但当某项功能启用时,所有与该功能相关的选项都应包含在内。这种结构我们可以通过分组分离选项+加入选项来实现。考虑:
interface Base {
title: string
}
interface Pager {
pager?: {
limit: number
count: number
}
}
interface Sort {
sorter?: {
columns: string[] // example property
}
}
type Options = Pager & Sort & Base;
function func(args: Options) {
if (args.pager) {
pager({ limit: args.pager.limit, count: args.pager.count });
}
if (args.sorter) {
sorter(args.sorter.columns)
}
}
func({
title: 'title',
pager: {count: 2, limit: 10} // all fields its ok
})
func({
title: 'title',
pager: {count: 2} // error limit is missing
})
现在我们可以将
pager
和sorter
放在一起,当您有pager
时,您需要根据需要放置所有与之相关的选项。我们在这里看到的问题与联合元素之间没有适当的区别有关。我们在两个成员之间有重叠(funcpagerags&BaseArgs)| BaseArgs
,重叠相等BaseArgs
。非常重要的是:
在比较函数参数的类型时,如果源参数可分配给目标参数,则分配成功,反之亦然
这意味着什么-如果我们的类型可以分配给想要的类型,或者想要的类型可以分配给我们的参数类型,那么您可以传递它。考虑测试:
type ArgType = {
title: "something",
enablePager: true
}
type IsAssignable = ArgType extends FuncArgs ? true : false; // true, can be passed
所以您要传递的类型是可分配给想要的类型的,那么TS允许传递它。不要问我为什么,这是设计决策,你可以把它理解为一种妥协,更严格会阻止许多想要的行为,至少我在上面链接的TS文档中已经说明了这一点。可以肯定的是,现在代码中存在的问题将使我们成为运行时错误
为了解决这个问题,我们需要创建一个没有重叠的适当的有歧视的联盟
interface BaseArgs {
title: string
}
interface OnlyTitle extends BaseArgs {
kind: 'TITLE'
}
interface FuncPagerArgs extends BaseArgs {
kind: 'PAGER'
enablePager: true
limit: number
count: number
}
type FuncArgs = OnlyTitle | FuncPagerArgs;
function func(args: FuncArgs) {
if (args.kind === 'PAGER') {
pager({ limit: args.limit, count: args.count });
}
}
interface PagerArgs {
limit: number
count: number
}
function pager(args: PagerArgs) {
}
func({
kind: "TITLE",
enablePager: true
}) // error
func({
kind: "TITLE",
title: 'title'
}) // correct
我所做的是以kind
属性的形式,它将允许在适当的成员上不存在任何重叠。这意味着现在您只能使用或一个或另一个变体,类型永远不会重叠
在评论之后编辑
作者在评论中表示,他需要将所有选项组合在一起,但当某项功能启用时,所有与该功能相关的选项都应包含在内。这种结构我们可以通过分组分离选项+加入选项来实现。考虑:
interface Base {
title: string
}
interface Pager {
pager?: {
limit: number
count: number
}
}
interface Sort {
sorter?: {
columns: string[] // example property
}
}
type Options = Pager & Sort & Base;
function func(args: Options) {
if (args.pager) {
pager({ limit: args.pager.limit, count: args.pager.count });
}
if (args.sorter) {
sorter(args.sorter.columns)
}
}
func({
title: 'title',
pager: {count: 2, limit: 10} // all fields its ok
})
func({
title: 'title',
pager: {count: 2} // error limit is missing
})
现在我们可以将
pager
和sorter
放在一起,当您有pager
时,您需要根据需要放置与之相关的所有选项。这种有区别的联合完全阻止了一次执行多个操作的能力。我的问题是我想有多个功能切换,每个都有自己所需的属性。如果必须使用字符串文字作为判别式,则不能使用多个字符。没有办法使用数组或对象作为判别式吗<代码>功能:{pager:true}或功能:[“pager”]
这样,另一个arg对象可以是功能:[“pager”,“sorting”]
等?感谢您的澄清。我更新了我的答案,我想这就是你需要的。那种歧视性的结合完全阻止了一次做多个的能力。我的问题是我想有多个功能切换,每个都有自己所需的属性。如果必须使用字符串文字作为判别式,则不能使用多个字符。没有办法使用数组或对象作为判别式吗<代码>功能:{pager:true}或功能:[“pager”]
这样,另一个arg对象可以是功能:[“pager”,“sorting”]
等?感谢您的澄清。我更新了我的答案,我想这就是你需要的。