我对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
类型?
答案 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"
。
答案 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');
}