我具有第一个参数确定第二个参数的功能。
它的行为类似于Foo
type stringF = (type: 'str', value: string) => void
type numberF = (type: 'num', value: number) => void
type booleanF = (type: 'bool', value: boolean) => void
...
...
declare const Foo: stringF & numberF & booleanF //& etc..
共有6种功能类型。这是痛苦的,但可以控制。但是,现在有一个额外的参数作为第一个参数,用于指定是否应为数组。
所以变成了:
type stringF = (arr: false, type: 'str', value: string) => void
type numberF = (arr, false, type: 'num', value: number) => void
type booleanF = (arr, false, type: 'bool', value: boolean) => void
...
type stringF = (arr: true, type: 'str', value: string[]) => void
type numberF = (arr, true, type: 'num', value: number[]) => void
type booleanF = (arr, true, type: 'bool', value: boolean[]) => void
...
现在有12种功能类型。正确键入函数似乎并不值得麻烦
有没有更简单的方法来创建条件函数签名?
答案 0 :(得分:1)
您可以使用条件类型为所有可能性创建单个签名:
type StringToType = {
str: string,
num: number,
bool: boolean
}
type MakeArrayIfTrue<TCondition, T> = TCondition extends true ? T[] :T;
type fn = <MakeArray extends boolean, TypeKey extends keyof StringToType>(arr: MakeArray, type: TypeKey, value: MakeArrayIfTrue<MakeArray, StringToType[TypeKey]>) => void
declare let fn : fn;
fn(true, "str", [""]);
fn(true, "bool", [""]); // error
fn(false, "str", [""]); // error
如果参数是联合,则其行为与多次重载有些不同。例如,这是有效的:
declare let b: boolean;
declare let strOrBool: "str" | "bool";
// Last parameter ca be boolean | string | boolean[] | string[]
fn(b, strOrBool, "") //ok
fn(b, strOrBool, [""]) //ok
fn(b, strOrBool, true) //ok
fn(b, strOrBool, 1) //this is still an error
如果您想限制这种行为,我们可以变得更有创意,首先创建所有可能签名的并集,然后使用UnionToIntersection
返回行为类似于带有重载功能的类型:>
type StringToType = {
str: string,
num: number,
bool: boolean
}
type MakeArrayIfTrue<TCondition, T> = TCondition extends true ? T[] :T;
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type FnHelper<MakeArray extends boolean = boolean, TypeKey extends keyof StringToType = keyof StringToType> =
MakeArray extends any ? TypeKey extends any ? (arr: MakeArray, type: TypeKey, value: MakeArrayIfTrue<MakeArray, StringToType[TypeKey]>) => void: never: never;
type fn = UnionToIntersection<FnHelper>;
declare let fn : fn;
fn(true, "str", [""]);
fn(true, "bool", [""]); // error
fn(false, "str", [""]); // error
declare let b: boolean;
declare let strOrBool: "str" | "bool";
fn(b, strOrBool, "") //error
fn(b, strOrBool, [""]) //error
fn(b, strOrBool, true) //error
答案 1 :(得分:0)
在这种情况下,您应该使用Generic。因此,您的功能签名可能如下所示:
function myFunc<T>(value: T|T[]): void
它可以是数组,也可以不是数组,您只需要在函数中检查它即可。类型T代表所有不同的值类型。