【问题标题】:Assign Typescript type in switch statement在 switch 语句中分配 Typescript 类型
【发布时间】:2018-08-03 15:55:44
【问题描述】:

尝试编写一个通用函数函数返回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 中的参数。在它之外的错误。

【问题讨论】:

  • 可能与错误无关,但scaleTime 使用Date 作为域元素。或者您对 1970-01-01 之后的第一个毫秒感兴趣。您分配不返回结果的 lambda 的结果。
  • @rioV8 感谢您的提醒。尝试更改为domain: Array&lt;number | Date&gt;;,但仍然出现相同的错误。似乎typescriptd3-scale 类型中不断链接回domain(): number[]。当它应该看到它也可以有domain(domain: Array&lt;number | { valueOf(): number }&gt;): this;。我基本上不得不在各自的 case 语句中复制代码
  • 生成的 JavaScript 是什么样子的?
  • 它不会编译。 src/app/Components/D3/utils/scale.ts:55:5 - error TS2554: Expected 0 arguments, but got 1.
  • scale.ts::55 行的代码是什么?

标签: typescript d3.js


【解决方案1】:

问题在于 ScaleLinear.domainScaleTime.domain 的 1-argument 重载具有不同的参数类型(即使 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 非常相似,但相似度不足以让我将其投票为重复。

【讨论】:

  • 谢谢。最后我坚持使用重复的 if 语句,但非常感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 2014-11-01
  • 2020-01-14
  • 2012-05-26
  • 1970-01-01
  • 2019-04-12
相关资源
最近更新 更多