在switch语句,功能请求中检查Typescript类型,还是我做错了?

时间:2019-02-20 12:43:51

标签: typescript

为什么打字稿不知道f1传递“ SpecificStringObj”类型的参数时返回字符串?

interface F {
  (s: AnyStringObj | SpecificStringObj): string | number;
}

interface AnyStringObj {
  text: string;
}

interface SpecificStringObj {
  text: "specificity";
}

const f1: F = s => {
  switch (s.text) {
    case "specificity":
      return "s";
    default:
      return 1;
  }
};

const stringObj: SpecificStringObj = {
  text: "specificity"
};

const newStringObj: AnyStringObj = { text: f1(stringObj) };

此Typescript代码在对象的最后一行 .text 上失败,错误消息是:

[ts]
Type 'string | number' is not assignable to type 'string'.
  Type 'number' is not assignable to type 'string'. [2322]
t.tsx(6, 3): The expected type comes from property 'text' which is declared here on type 'AnyStringObj'
(property) AnyStringObj.text: string

我可以通过以下方法解决此问题:

const newStringObj: AnyStringObj = { text: f1(stringObj) as string };

我的问题是:为什么打字稿不知道自从我传递“ SpecificStringObj”以来函数将返回字符串?


其他问题:这是否适合功能请求?

2 个答案:

答案 0 :(得分:2)

您正在寻找function overloading

interface AnyStringObj {
  text: string;
}

interface SpecificStringObj {
  text: "specificity";
}

function f1(s: SpecificStringObj): string;  
function f1(s: AnyStringObj): number;
function f1(s: AnyStringObj | SpecificStringObj): string | number { 
  switch (s.text) {
    case "specificity":
          return "s";
    default:
      return 1;
  }
}


const stringObj: SpecificStringObj = {
  text: "specificity"
};

const newStringObj: AnyStringObj = { text: f1(stringObj) };

Live example

答案 1 :(得分:1)

Typescript不会做这种分析之王。当试图找出f1返回的内容时,它只会查看函数的签名。在签名中,anyStringObjstring之间没有明确的关系(事实是它们在参数中位于相同位置,并且返回并集并没有关系)。

要帮助编译器完成此任务,可以使用重载或条件类型:

重载版本:

interface f {
    (s: specificStringObj): string;
    (s: anyStringObj): number;
    (s: anyStringObj | specificStringObj): string | number;
}

interface anyStringObj {
    text: string;
}

interface specificStringObj {
    text: "specificity";
}

const f1: f = ((s:anyStringObj | specificStringObj): string | number => {
    switch (s.text) {
        case "specificity":
            return "s";
        default:
            return 1;
    }
}) as f;

const stringObj: specificStringObj = {
    text: "specificity"
};

const newStringObj: anyStringObj = { text: f1(stringObj) };

条件类型版本

interface f {
    <T extends anyStringObj | specificStringObj>(s: T):  T extends specificStringObj ? string : number;
}

interface anyStringObj {
    text: string;
}

interface specificStringObj {
    text: "specificity";
}

const f1: f = ((s:anyStringObj | specificStringObj): string | number => {
    switch (s.text) {
        case "specificity":
            return "s";
        default:
            return 1;
    }
}) as f;

const stringObj: specificStringObj = {
    text: "specificity"
};

const newStringObj: anyStringObj = { text: f1(stringObj) };