打字稿中的条件函数参数
conditional function arguments in typescript
是否可以根据第一个参数类型设置分生孢子所需的参数类型:
type ConditionalRequiredArg<T, P> = T extends string ? P | undefined : P;
function func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>) {}
func('foo'); // Error: Expected 2 arguments, but got 1.
理论上,上述函数不应该需要第二个参数,但确实如此!
编辑:我知道“?”对于可选参数类型,但我想让它有条件地利用编译器错误和建议。
定义函数的第二个参数的第一个解决方案是
使用 ?
运算符将其标记为可选,并具有以下内容:
// ...
function func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>) {}
// ...
但是,如果您想进行更多更改,请查看以下内容:
/*
* You could remove the conditional type to get a better inference on the generics
* that are used and simply check the typeof _arg1 and if it is string as you had
* defined in the ConfitionalRequiredArg it will use a type in the generic arg
* you would then have to provide
*/
function func<P>(_arg1: string | number, _arg2?: typeof _arg1 extends string ? P | undefined : P) {}
func<string>('foo', 4); // ts error 4 is not assignable to type string | undefined
最后,要使参数可选,请使用 ?
运算符。
我认为你混淆了两种不同的东西。
func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>)
意味着该函数需要 2 个参数,其中第二个参数可能具有未定义的类型,意思是:
_arg2 = undefined
,其中字段 _arg2
已经声明。
但您希望该字段不被声明。
_arg2 = undefined
不等同于说:
func<T, P>(_arg1: string | number, undefined)
对于这个用例,您可以使用 ?如下:
func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>)
编辑:
类型和参数是两个不同的东西。类型定义了值的类型,而参数是一个字段。
虽然这不是一个好的做法,但您也可以使用 undefined 手动初始化字段,如下所示:
func<T, P>(_arg1: string | number, _arg2: string = undefined)
但这最终和_arg2?
一样
类型 undefined
就像说“该字段不包含任何内容”或更好地说“该字段包含未定义”,而字段 undefined
是“该字段不存在”
您始终可以使用 signature overloading 来阻止用户直接使用实现签名:
function func<P>(_arg1: string, _arg2?: P)
function func<P>(_arg1: number, _arg2: P)
function func<P>(_arg1: string | number, _arg2?: P) { }
此代码强制用户选择使用第一个签名或第二个签名,而不是实施的第三个签名。
func('foo', 1); // success
func('foo'); // success
func(1, 1); // success
func(1); // Error: Argument of type 'number' is not assignable to parameter of type 'string'
正如@daylily 所说,如果您能够使用签名重载语法,那绝对是正确的选择。但是,如果您需要推断泛型,那么我通常会有条件地生成一个元组:
function assertPerson<
Age extends number
>(
...args: 0 extends Age ? [age: Age] : [age: Age, name: string]
) {
const [age, maybeName] = args; // [number, string | undefined]
}
assertPerson(2, "hey");
assertPerson(0)
是否可以根据第一个参数类型设置分生孢子所需的参数类型:
type ConditionalRequiredArg<T, P> = T extends string ? P | undefined : P;
function func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>) {}
func('foo'); // Error: Expected 2 arguments, but got 1.
理论上,上述函数不应该需要第二个参数,但确实如此!
编辑:我知道“?”对于可选参数类型,但我想让它有条件地利用编译器错误和建议。
定义函数的第二个参数的第一个解决方案是
使用 ?
运算符将其标记为可选,并具有以下内容:
// ...
function func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>) {}
// ...
但是,如果您想进行更多更改,请查看以下内容:
/*
* You could remove the conditional type to get a better inference on the generics
* that are used and simply check the typeof _arg1 and if it is string as you had
* defined in the ConfitionalRequiredArg it will use a type in the generic arg
* you would then have to provide
*/
function func<P>(_arg1: string | number, _arg2?: typeof _arg1 extends string ? P | undefined : P) {}
func<string>('foo', 4); // ts error 4 is not assignable to type string | undefined
最后,要使参数可选,请使用 ?
运算符。
我认为你混淆了两种不同的东西。
func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>)
意味着该函数需要 2 个参数,其中第二个参数可能具有未定义的类型,意思是:
_arg2 = undefined
,其中字段 _arg2
已经声明。
但您希望该字段不被声明。
_arg2 = undefined
不等同于说:
func<T, P>(_arg1: string | number, undefined)
对于这个用例,您可以使用 ?如下:
func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>)
编辑:
类型和参数是两个不同的东西。类型定义了值的类型,而参数是一个字段。
虽然这不是一个好的做法,但您也可以使用 undefined 手动初始化字段,如下所示:
func<T, P>(_arg1: string | number, _arg2: string = undefined)
但这最终和_arg2?
类型 undefined
就像说“该字段不包含任何内容”或更好地说“该字段包含未定义”,而字段 undefined
是“该字段不存在”
您始终可以使用 signature overloading 来阻止用户直接使用实现签名:
function func<P>(_arg1: string, _arg2?: P)
function func<P>(_arg1: number, _arg2: P)
function func<P>(_arg1: string | number, _arg2?: P) { }
此代码强制用户选择使用第一个签名或第二个签名,而不是实施的第三个签名。
func('foo', 1); // success
func('foo'); // success
func(1, 1); // success
func(1); // Error: Argument of type 'number' is not assignable to parameter of type 'string'
正如@daylily 所说,如果您能够使用签名重载语法,那绝对是正确的选择。但是,如果您需要推断泛型,那么我通常会有条件地生成一个元组:
function assertPerson<
Age extends number
>(
...args: 0 extends Age ? [age: Age] : [age: Age, name: string]
) {
const [age, maybeName] = args; // [number, string | undefined]
}
assertPerson(2, "hey");
assertPerson(0)