有没有办法用可选参数缩小打字稿重载?
Is there a way to narrow typescript overloads with optional parameters?
我正在尝试执行以下操作:
interface RgbColor {
r: number;
g: number;
b: number;
}
function rgbToHex(r: RgbColor, g?: undefined, b?: undefined): string
function rgbToHex(r: number, g: number, b: number): string
function rgbToHex(r: number|RgbColor, g?: number, b?: number): string {
if (r instanceof Object) {
// must be RgbColor
g = r.g;
b = r.b;
r = r.r;
}
// A) r was an RgbColor and we've already set r, g, and b to numbers in the if block
// B) we're meeting the second overload and r, g, and b are all numbers
// either way we know they are all numbers now
let rHex = r.toString(16);
let gHex = g.toString(16); // ERROR: Object is possibly 'undefined'.
let bHex = b.toString(16); // ERROR: Object is possibly 'undefined'.
if (rHex.length == 1) rHex = "0" + rHex;
if (gHex.length == 1) gHex = "0" + gHex;
if (bHex.length == 1) bHex = "0" + bHex;
return "#" + rHex + gHex + bHex;
}
我在 ERROR
条评论指出的行中收到错误。
从 javascript 的角度来看,该功能很好:
function rgbToHex(r , g, b) {
if (r instanceof Object) {
g = r.g;
b = r.b;
r = r.r;
}
let rHex = r.toString(16);
let gHex = g.toString(16);
let bHex = b.toString(16);
if (rHex.length == 1) rHex = "0" + rHex;
if (gHex.length == 1) gHex = "0" + gHex;
if (bHex.length == 1) bHex = "0" + bHex;
return "#" + rHex + gHex + bHex;
}
rgbToHex({ r: 120, g: 50, b: 5 }) // "#783205"
rgbToHex(120, 50, 5) // "#783205"
我的问题是如何设置函数签名,这样它就可以正常工作,而无需进行任何强制转换,也无需在函数体中设置任何冗余变量。即我想避免做 let gVal: number = g || (r as any).g;
.
另一种选择是将其拆分为两个函数,一个调用另一个;但我不会用 javascript 那样做,所以我必须用打字稿来做这件事似乎是错误的。
抱歉,如果这是重复的。我花了几个小时查看类似的问题,但找不到解决此问题的任何内容。
问题是,变量 g
和 b
将始终是 number | undefined
类型,如果不声明新变量,它们将无法永久重新分配。
您有 4 个选项:
- 使用非空断言运算符
!
,这意味着您需要编写 g!.toString(16)
而不是编写 g.toString(16)
,强制其类型为 number
。你也可以用类型转换来解决它。
- 你可以把它分成多个函数,提取rgb变量然后return原来的
rgbToHex
函数。
- 如@Oblosys 的回答中所述,您可以使用联合类型。
- 您可以在函数顶部创建一个新对象,在其中填充一个新的
RgbColor
对象。
经过更多的谷歌搜索、阅读其他 SO 问题并浏览打字稿 github 问题后,看起来这是打字稿中尚未实现的功能。
在函数外起作用的重载缩小还不适用于函数内:
// function definition for swapping between number and string types
function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number|string
{ ... }
const a = foo('string');
a.toPrecision(); // TS knows a is a number, so this has no errors
const b = foo(5);
b.toLowerCase(); // TS knows b is a string, so this has no errors
const c = Math.random() < .5 ? a : b; // TS knows c as string | number
// the actual implementation of an overloaded method does not count as
// one of the possible overloads, so calling foo with a variable of type (string|number)
// is not valid
const d = foo(c); // error on parameter 'c': No overload matches this call.
所以这一切都符合预期。但是当我们尝试实现 foo
时,我们发现在方法中没有应用相同的排除逻辑:
function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number | string {
return bar; // this is valid, it clearly should not be
}
看起来打字稿团队还没有在一个函数内进行代码分析,意识到该函数的重载,似乎严格执行了实现的签名。这显然是错误的。
QED:工具错误。等待修复。
我正在尝试执行以下操作:
interface RgbColor {
r: number;
g: number;
b: number;
}
function rgbToHex(r: RgbColor, g?: undefined, b?: undefined): string
function rgbToHex(r: number, g: number, b: number): string
function rgbToHex(r: number|RgbColor, g?: number, b?: number): string {
if (r instanceof Object) {
// must be RgbColor
g = r.g;
b = r.b;
r = r.r;
}
// A) r was an RgbColor and we've already set r, g, and b to numbers in the if block
// B) we're meeting the second overload and r, g, and b are all numbers
// either way we know they are all numbers now
let rHex = r.toString(16);
let gHex = g.toString(16); // ERROR: Object is possibly 'undefined'.
let bHex = b.toString(16); // ERROR: Object is possibly 'undefined'.
if (rHex.length == 1) rHex = "0" + rHex;
if (gHex.length == 1) gHex = "0" + gHex;
if (bHex.length == 1) bHex = "0" + bHex;
return "#" + rHex + gHex + bHex;
}
我在 ERROR
条评论指出的行中收到错误。
从 javascript 的角度来看,该功能很好:
function rgbToHex(r , g, b) {
if (r instanceof Object) {
g = r.g;
b = r.b;
r = r.r;
}
let rHex = r.toString(16);
let gHex = g.toString(16);
let bHex = b.toString(16);
if (rHex.length == 1) rHex = "0" + rHex;
if (gHex.length == 1) gHex = "0" + gHex;
if (bHex.length == 1) bHex = "0" + bHex;
return "#" + rHex + gHex + bHex;
}
rgbToHex({ r: 120, g: 50, b: 5 }) // "#783205"
rgbToHex(120, 50, 5) // "#783205"
我的问题是如何设置函数签名,这样它就可以正常工作,而无需进行任何强制转换,也无需在函数体中设置任何冗余变量。即我想避免做 let gVal: number = g || (r as any).g;
.
另一种选择是将其拆分为两个函数,一个调用另一个;但我不会用 javascript 那样做,所以我必须用打字稿来做这件事似乎是错误的。
抱歉,如果这是重复的。我花了几个小时查看类似的问题,但找不到解决此问题的任何内容。
问题是,变量 g
和 b
将始终是 number | undefined
类型,如果不声明新变量,它们将无法永久重新分配。
您有 4 个选项:
- 使用非空断言运算符
!
,这意味着您需要编写g!.toString(16)
而不是编写g.toString(16)
,强制其类型为number
。你也可以用类型转换来解决它。 - 你可以把它分成多个函数,提取rgb变量然后return原来的
rgbToHex
函数。 - 如@Oblosys 的回答中所述,您可以使用联合类型。
- 您可以在函数顶部创建一个新对象,在其中填充一个新的
RgbColor
对象。
经过更多的谷歌搜索、阅读其他 SO 问题并浏览打字稿 github 问题后,看起来这是打字稿中尚未实现的功能。
在函数外起作用的重载缩小还不适用于函数内:
// function definition for swapping between number and string types
function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number|string
{ ... }
const a = foo('string');
a.toPrecision(); // TS knows a is a number, so this has no errors
const b = foo(5);
b.toLowerCase(); // TS knows b is a string, so this has no errors
const c = Math.random() < .5 ? a : b; // TS knows c as string | number
// the actual implementation of an overloaded method does not count as
// one of the possible overloads, so calling foo with a variable of type (string|number)
// is not valid
const d = foo(c); // error on parameter 'c': No overload matches this call.
所以这一切都符合预期。但是当我们尝试实现 foo
时,我们发现在方法中没有应用相同的排除逻辑:
function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number | string {
return bar; // this is valid, it clearly should not be
}
看起来打字稿团队还没有在一个函数内进行代码分析,意识到该函数的重载,似乎严格执行了实现的签名。这显然是错误的。
QED:工具错误。等待修复。