有没有更简单的方法来编写多个条件函数签名?
Is there an easier way of writing multiple condition function signatures?
我有第一个参数决定第二个参数的函数。
它的行为类似于 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种函数类型。正确输入函数似乎不值得麻烦
有没有更简单的方法来制作条件函数签名?
您可以使用条件类型为所有可能性创建单个签名:
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
如果你想限制这种行为,我们可以更有创意,首先创建一个所有可能签名的联合,然后使用 返回一个行为类似于具有重载的函数的类型:
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
在这种情况下,您应该使用 Generic。所以你的函数签名可能是这样的:
function myFunc<T>(value: T|T[]): void
它可以是数组也可以不是数组,你只需要在你的函数中检查它。而类型 T 代表所有不同的值类型。
我有第一个参数决定第二个参数的函数。
它的行为类似于 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种函数类型。正确输入函数似乎不值得麻烦
有没有更简单的方法来制作条件函数签名?
您可以使用条件类型为所有可能性创建单个签名:
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
如果你想限制这种行为,我们可以更有创意,首先创建一个所有可能签名的联合,然后使用
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
在这种情况下,您应该使用 Generic。所以你的函数签名可能是这样的:
function myFunc<T>(value: T|T[]): void
它可以是数组也可以不是数组,你只需要在你的函数中检查它。而类型 T 代表所有不同的值类型。