如何使未定义的参数不需要?
How can I make an undefined parameter not required?
我试图让未定义的值成为可选的,而不是可选的值。我的完美示例是:
type TypeObj = {
a: undefined;
b: number;
c: string;
}
call("a"); call("b", 1); call("c", "3"); // should work
call("b", "a"); call("c", 3) // shouldn't work
call("b"); call("c") // also shouldn't work
但我目前的方法(第二个参数是可选的)允许 call
在没有第二个参数的情况下使用 b 和 c,这是我不想要的。
function call<K extends keyof TypeObj = keyof TypeObj>(key: K, param?: TypeObj[K]) {
}
call("a"); call("b", 1); call("c", "3"); // works (good)
call("b", "a"); call("c", 3) // doesn't work (good)
call("b"); call("c") // works (don't want that)
这种事情基本上需要 call()
有多个调用签名。
传统上,这需要您将 call()
设为 overloaded function, but you can also do it by having the function accept a tuple-typed rest parameter.
这是一种方法:
type OptionalIfUndefined<T> =
undefined extends T ? [param?: T] : [param: T];
function call<K extends keyof TypeObj>(
key: K, ...[param]: OptionalIfUndefined<TypeObj[K]>
) {
const _param = param as TypeObj[K]; // <-- might need this
}
OptionalIfUndefined<T>
类型是conditional type that checks if undefined
is assignable to T
. If so, it evaluates to a single-element tuple with an optional element of type T
;否则,它计算为 single-element 元组,其中 required 元素类型为 T
.
然后 call()
被赋予一个类型为 OptionalIfUndefined<TypeObj[K]>
的剩余参数。我们使用 destructuring assignment 以便 param
是一个保存单个元素的变量名,因为这就是我们真正想要的(保存它的实际数组对我们没有用)。
在您的示例中,您没有在 call()
的实现中执行任何操作,但是如果您期望 param
被称为 TypeObj[K]
类型,您会感到失望。通用条件类型对编译器来说本质上是不透明的,因此它不知道 typeof param
会比 TypeObj[K] | undefined
更窄。如果您需要这样的功能,您需要 assert 像 const _param = param as TypeObj[K]
一样,然后使用 _param
而不是 param
(或者如果需要交换名称)。
好吧,让我们确保它有效:
call("a") // okay
call("a", undefined) // okay
call("b", 1); // okay
call("b") // error
call("c", "a"); // okay
call("c") // error
看起来不错!
我试图让未定义的值成为可选的,而不是可选的值。我的完美示例是:
type TypeObj = {
a: undefined;
b: number;
c: string;
}
call("a"); call("b", 1); call("c", "3"); // should work
call("b", "a"); call("c", 3) // shouldn't work
call("b"); call("c") // also shouldn't work
但我目前的方法(第二个参数是可选的)允许 call
在没有第二个参数的情况下使用 b 和 c,这是我不想要的。
function call<K extends keyof TypeObj = keyof TypeObj>(key: K, param?: TypeObj[K]) {
}
call("a"); call("b", 1); call("c", "3"); // works (good)
call("b", "a"); call("c", 3) // doesn't work (good)
call("b"); call("c") // works (don't want that)
这种事情基本上需要 call()
有多个调用签名。
传统上,这需要您将 call()
设为 overloaded function, but you can also do it by having the function accept a tuple-typed rest parameter.
这是一种方法:
type OptionalIfUndefined<T> =
undefined extends T ? [param?: T] : [param: T];
function call<K extends keyof TypeObj>(
key: K, ...[param]: OptionalIfUndefined<TypeObj[K]>
) {
const _param = param as TypeObj[K]; // <-- might need this
}
OptionalIfUndefined<T>
类型是conditional type that checks if undefined
is assignable to T
. If so, it evaluates to a single-element tuple with an optional element of type T
;否则,它计算为 single-element 元组,其中 required 元素类型为 T
.
然后 call()
被赋予一个类型为 OptionalIfUndefined<TypeObj[K]>
的剩余参数。我们使用 destructuring assignment 以便 param
是一个保存单个元素的变量名,因为这就是我们真正想要的(保存它的实际数组对我们没有用)。
在您的示例中,您没有在 call()
的实现中执行任何操作,但是如果您期望 param
被称为 TypeObj[K]
类型,您会感到失望。通用条件类型对编译器来说本质上是不透明的,因此它不知道 typeof param
会比 TypeObj[K] | undefined
更窄。如果您需要这样的功能,您需要 assert 像 const _param = param as TypeObj[K]
一样,然后使用 _param
而不是 param
(或者如果需要交换名称)。
好吧,让我们确保它有效:
call("a") // okay
call("a", undefined) // okay
call("b", 1); // okay
call("b") // error
call("c", "a"); // okay
call("c") // error
看起来不错!