尝试编写泛型函数以返回d3 scale
。但由于在switch
语句后读取了错误的类型而收到以下错误。
import * as D3Scale from 'd3-scale';
enum scaleIdentites {
linear,
time,
}
interface ScaleProps {
scaleIdentity: scaleIdentites;
range: number[];
domain: number[];
}
export const scale = ({ scaleIdentity, domain }: ScaleProps) => {
let scaleFunction: D3Scale.ScaleLinear<number, number> | D3Scale.ScaleTime<number, number>;
switch (scaleIdentity) {
case scaleIdentites.linear:
scaleFunction = D3Scale.scaleLinear();
scaleFunction.domain([1, 2]); // correctly reads the correct type and doesnt error.
break;
case scaleIdentites.time:
scaleFunction = D3Scale.scaleTime();
scaleFunction.domain([1, 2]); // correctly reads the correct type and doesnt error.
break;
default: {
throw new Error(`Unknow scale ${scaleIdentity}`);
}
}
if (domain) {
scaleFunction.domain(domain); // error as saying should have 0 parameters.
}
};
在case
块中,它可以让我正确使用domain
中的参数。外面有错误。
答案 0 :(得分:2)
问题是ScaleLinear.domain
和ScaleTime.domain
的1参数重载具有不同的参数类型(即使number[]
可以同时分配给这两种参数),并且当您具有并集类型时, TypeScript keeps only the call signatures with identical parameter types,在这种情况下只是0参数重载。
在此示例中,在两种情况下重复if (domain) { scaleFunction.domain(domain); }
逻辑对我来说似乎都不错。如果您确实想避免重复该if
语句,则可以执行以下操作:
export const scale = ({ scaleIdentity, domain }: ScaleProps) => {
let scaleFunction: D3Scale.ScaleLinear<number, number> | D3Scale.ScaleTime<number, number>;
let setDomain: (domain: number[]) => void;
switch (scaleIdentity) {
case scaleIdentites.linear:
const linearFunction = scaleFunction = D3Scale.scaleLinear();
setDomain = (domain) => linearFunction.domain(domain);
break;
case scaleIdentites.time:
const timeFunction = scaleFunction = D3Scale.scaleTime();
setDomain = (domain) => timeFunction.domain(domain);
break;
default: {
throw new Error(`Unknow scale ${scaleIdentity}`);
}
}
if (domain) {
setDomain(domain);
}
};
请注意使用新的const
变量,因为let
变量的范围不会传播到回调中。
Typescript no compatible call signatures error with union types非常相似,但不足以让我将此重复投票。