为什么 Typescript 会尝试将条件类型的一个分支与另一个匹配?
Why Typescript tries to match one branch of conditional type with another?
我有一个小的实用函数,现在我正在尝试使用泛型为其编写更具体的类型。
代码如下:
/* global localStorage */
const ls = localStorage
export type ParsedJSON<T> = T | null
export type Falsy = false | undefined
function get<T = any> (
key: string,
parseJSON?: boolean
): typeof parseJSON extends Falsy ? string : ParsedJSON<T> {
const value = ls.getItem(key) ?? ''
if (parseJSON === true) {
let result: ParsedJSON<T> = null
try {
result = JSON.parse(value)
} catch (err) {}
return result
} else if ((parseJSON === false)) {
return value
}
return null
}
else 分支出现错误:Type 'string' is not assignable to type 'ParsedJSON<T>'
。
(else 分支在这里有点多余,但我明确添加了它以调查此错误)。
这里没看懂,为什么TS会尝试匹配string
类型和ParsedJSON<T>
类型
对我来说唯一合理的解释是false
不能分配给Falsy
类型,所以return类型被计算为ParsedJSON<T>
。但我已经检查过情况并非如此:
所以,请帮助我了解这里发生了什么。 )
谢谢。
看起来发生的事情是 TS 评估类型表达式 typeof parseJSON extends Falsy ? string : ParsedJSON<T>
不是作为调用函数时要使用通用参数评估的条件表达式,而是立即基于有关的当前可用信息函数。
有了这些知识,我们就可以确定编译器推断出的 return 类型是什么。表达式为
typeof parseJSON extends Falsy ? string : ParsedJSON<T>
parseJSON
在评估时的类型是 boolean | undefined
,因此它 而不是 扩展 Falsy
即 false | undefined
,因此类型更窄。
因此get
的return类型确定为:ParsedJSON<T>
.
我能想到的基于调用站点实际参数值的条件 return 类型的唯一方法是,正如@Nishant 建议的那样,函数重载。例如:
function get<T = any>(key: string, parseJSON: true): ParsedJSON<T>
function get<T = any>(key: string, parseJSON?: false): string
function get<T = any>(key: string, parseJSON?: boolean) {
const value = ls.getItem(key) ?? ''
if (parseJSON === true) {
let result: ParsedJSON<T> = null
try {
result = JSON.parse(value)
} catch (err) { }
return result
} else if ((parseJSON === false)) {
return value
}
return null
}
现在函数将根据 parseJSON
的类型具有正确的 return 类型。
get<number>('', true) // => ParsedJSON<number>
get<number>('', false) // => string
get<number>('') // => string
我有一个小的实用函数,现在我正在尝试使用泛型为其编写更具体的类型。
代码如下:
/* global localStorage */
const ls = localStorage
export type ParsedJSON<T> = T | null
export type Falsy = false | undefined
function get<T = any> (
key: string,
parseJSON?: boolean
): typeof parseJSON extends Falsy ? string : ParsedJSON<T> {
const value = ls.getItem(key) ?? ''
if (parseJSON === true) {
let result: ParsedJSON<T> = null
try {
result = JSON.parse(value)
} catch (err) {}
return result
} else if ((parseJSON === false)) {
return value
}
return null
}
else 分支出现错误:Type 'string' is not assignable to type 'ParsedJSON<T>'
。
(else 分支在这里有点多余,但我明确添加了它以调查此错误)。
这里没看懂,为什么TS会尝试匹配string
类型和ParsedJSON<T>
类型
对我来说唯一合理的解释是false
不能分配给Falsy
类型,所以return类型被计算为ParsedJSON<T>
。但我已经检查过情况并非如此:
所以,请帮助我了解这里发生了什么。 ) 谢谢。
看起来发生的事情是 TS 评估类型表达式 typeof parseJSON extends Falsy ? string : ParsedJSON<T>
不是作为调用函数时要使用通用参数评估的条件表达式,而是立即基于有关的当前可用信息函数。
有了这些知识,我们就可以确定编译器推断出的 return 类型是什么。表达式为
typeof parseJSON extends Falsy ? string : ParsedJSON<T>
parseJSON
在评估时的类型是 boolean | undefined
,因此它 而不是 扩展 Falsy
即 false | undefined
,因此类型更窄。
因此get
的return类型确定为:ParsedJSON<T>
.
我能想到的基于调用站点实际参数值的条件 return 类型的唯一方法是,正如@Nishant 建议的那样,函数重载。例如:
function get<T = any>(key: string, parseJSON: true): ParsedJSON<T>
function get<T = any>(key: string, parseJSON?: false): string
function get<T = any>(key: string, parseJSON?: boolean) {
const value = ls.getItem(key) ?? ''
if (parseJSON === true) {
let result: ParsedJSON<T> = null
try {
result = JSON.parse(value)
} catch (err) { }
return result
} else if ((parseJSON === false)) {
return value
}
return null
}
现在函数将根据 parseJSON
的类型具有正确的 return 类型。
get<number>('', true) // => ParsedJSON<number>
get<number>('', false) // => string
get<number>('') // => string