类型'string |的参数“未定义”不可分配给类型为“未命名”的参数|空|未定义”

时间:2018-11-25 21:22:53

标签: typescript type-inference

我对TypeScript的类型推断一无所知。我认为这应该是有效的,并且不需要我指定T的类型:

export const deflt = <T>(val: (T | undefined | null), defaultVal: T): T => {
  if (val === undefined || val === null) {
    return defaultVal;
  }
  return val;
}

function maybeLabelName(name: string | undefined) {
  return deflt(name, 'untitled');
}

对deflt的调用失败,并出现以下错误:

Argument of type 'string | undefined' is not assignable to parameter of type '"untitled" | null | undefined'.
  Type 'string' is not assignable to type '"untitled" | null | undefined'. [2345]

我可以通过将deflt调用更改为以下其中一项来解决此问题:

// Option 1:
return deflt<string>(name, 'untitled');

// Option 2:
const s: string = 'untitled';
return deflt(name, s);

TypeScript是否应该自动推断string类型?

3 个答案:

答案 0 :(得分:2)

在这种情况下,我认为打字稿推断T的方式有点古怪。因为您指定了常量'untitled',所以编译器将推断T作为字符串文字类型'untitled',因为这是从中推断T的最简单的站点。然后,它将根据字符串文字类型检查另一个参数,并发现string无法分配给'untitled'。解决方法是通过添加与T的额外交集来降低推断{}时第二个参数的优先级:

export const deflt = <T>(val: (T | undefined | null), defaultVal: T & {} ): T => {
    if (val === undefined || val === null) {
        return defaultVal;
    }
    return val;
}

function maybeLabelName(name: string | undefined) {
    return deflt(name, 'untitled'); // T is string now
}

另一种解决方案(如果您无法更改原始功能)是将untitled明确声明为string,这基本上是您已经尝试过的方法。

function maybeLabelName(name: string | undefined) {
    return deflt(name, 'untitled' as string); // T is string now
}

答案 1 :(得分:0)

使用泛型时,可以通过两种不同方式“生成”参数。

以您的案例为例:

const deflt = <T>(val: (T | undefined | null), defaultVal: T): T

如果您使用:deflt<string>(a, b),则将a强制为string | undefined | null,将b强制为string

如果使用:deflt(a: string, b: "untitled"),则编译器将"untitled"理解为常量,而不是字符串。因此,b的类型为"untitled",从而使T的类型为"untitled"。当您使用a类型的string时,编译器无法将string强制转换为"untitled"

@Titian Cernicova-Dragomir answer

已经提供了解决方案

答案 2 :(得分:0)

您已将deflt声明为泛型函数,但已将其用作常规函数

const deflt = <T>(val: (T | undefined | null), defaultVal: T): T => {
    if (val === undefined || val === null) {
      return defaultVal;
    }
    return val;
}

function maybeLabelName(name?: string) {
    return deflt<typeof name>(name, 'untitled');
}