在switch语句中分配Typescript类型

时间:2018-08-02 07:28:56

标签: typescript d3.js

尝试编写泛型函数以返回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中的参数。外面有错误。

1 个答案:

答案 0 :(得分:2)

问题是ScaleLinear.domainScaleTime.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非常相似,但不足以让我将此重复投票。