类型缩小后类型不可分配给自身
Type is not assignable to itself after type narrowing
给定以下代码
type Test = string | boolean | string[] | boolean[]
function test (param: Test) {
if (!_.isArray(param)) {
param = [param]
}
return param
}
我收到以下错误
(parameter) param: string | boolean
Type 'string | boolean' is not assignable to type 'boolean'.
Type 'string' is not assignable to type 'boolean'.ts(2322)
解决方法是
type Test = string | boolean | (string | boolean)[]
但我不明白我的解决方案
换句话说,我有一个类型,它由两种任意类型和(我知道很糟糕)这些类型的数组组成。通过 (!_.isArray) 类型保护我(我知道不好)改变了参数。
在类型保护中,我的类型定义被缩小为 'string | boolean'。 Typescript 告诉我无法为这种类型分配我想要的值。
请大神指点理解错误及解决方法
谢谢
这里的问题是,一旦您确定 param
不是数组,当您获取该类型的值并将其放入数组时,它的类型将被限制为 string | boolean
文字 Typescript 将类型推断为 [string | boolean]
,这与 string[] | boolean[]
不同。如果您改为检查每种可能的类型,然后在单独的分支中使用相同的代码行:
type Test = string | boolean | string[] | boolean[]
function test(param: Test) {
if (typeof param === 'string') {
param = [param];
} else if (typeof param === 'boolean') {
param = [param];
}
return param
}
如果不清楚这些类型之间的区别,一个 ((string | boolean)[]
) 可以是一个包含字符串和布尔值混合的数组,而另一个 (string[] | boolean[]
)是一个只有字符串的数组,或者一个只有布尔值的数组。不幸的是,Typescript 在这种情况下不够聪明,无法意识到数组 [param]
本质上是同质的,因为它只有一个元素。
考虑这个解决方案:
type Test = string | boolean | string[] | boolean[]
const test = (param: Test) => Array.isArray(param) ? param : [param]
你不需要改变任何东西。我相信你甚至不需要在这里使用 lodash
只是我的意见:
对我来说,在条件语句
中没有 !
否定运算符的情况下,它的可读性更高
更新
感谢 @Paul Wheeler 纠正我。
这里是我的缩小类型解决方案
type Test = string | boolean | string[] | boolean[]
const strOrBool = (val: unknown): val is string | boolean =>
typeof val === 'string' || typeof val === 'boolean'
function test<T extends string>(param: T): [T]
function test<T extends boolean>(param: T): [T]
function test<T extends string, U extends T[]>(param: [...U]): U
function test<T extends boolean, U extends T[]>(param: [...U]): U
function test<T extends Test>(param: T) {
return strOrBool(param) ? [param] : param
}
const result = test(true) // [true]
const result2 = test('hello') // ["hello"]
const result3 = test(['hello']) // ["hello"]
const result4 = test([true]) // [true]
顺便说一句,typescript 不能很好地处理变异值,它可能会导致错误
给定以下代码
type Test = string | boolean | string[] | boolean[]
function test (param: Test) {
if (!_.isArray(param)) {
param = [param]
}
return param
}
我收到以下错误
(parameter) param: string | boolean Type 'string | boolean' is not assignable to type 'boolean'. Type 'string' is not assignable to type 'boolean'.ts(2322)
解决方法是
type Test = string | boolean | (string | boolean)[]
但我不明白我的解决方案
换句话说,我有一个类型,它由两种任意类型和(我知道很糟糕)这些类型的数组组成。通过 (!_.isArray) 类型保护我(我知道不好)改变了参数。
在类型保护中,我的类型定义被缩小为 'string | boolean'。 Typescript 告诉我无法为这种类型分配我想要的值。
请大神指点理解错误及解决方法
谢谢
这里的问题是,一旦您确定 param
不是数组,当您获取该类型的值并将其放入数组时,它的类型将被限制为 string | boolean
文字 Typescript 将类型推断为 [string | boolean]
,这与 string[] | boolean[]
不同。如果您改为检查每种可能的类型,然后在单独的分支中使用相同的代码行:
type Test = string | boolean | string[] | boolean[]
function test(param: Test) {
if (typeof param === 'string') {
param = [param];
} else if (typeof param === 'boolean') {
param = [param];
}
return param
}
如果不清楚这些类型之间的区别,一个 ((string | boolean)[]
) 可以是一个包含字符串和布尔值混合的数组,而另一个 (string[] | boolean[]
)是一个只有字符串的数组,或者一个只有布尔值的数组。不幸的是,Typescript 在这种情况下不够聪明,无法意识到数组 [param]
本质上是同质的,因为它只有一个元素。
考虑这个解决方案:
type Test = string | boolean | string[] | boolean[]
const test = (param: Test) => Array.isArray(param) ? param : [param]
你不需要改变任何东西。我相信你甚至不需要在这里使用 lodash
只是我的意见: 对我来说,在条件语句
中没有!
否定运算符的情况下,它的可读性更高
更新
感谢 @Paul Wheeler 纠正我。
这里是我的缩小类型解决方案
type Test = string | boolean | string[] | boolean[]
const strOrBool = (val: unknown): val is string | boolean =>
typeof val === 'string' || typeof val === 'boolean'
function test<T extends string>(param: T): [T]
function test<T extends boolean>(param: T): [T]
function test<T extends string, U extends T[]>(param: [...U]): U
function test<T extends boolean, U extends T[]>(param: [...U]): U
function test<T extends Test>(param: T) {
return strOrBool(param) ? [param] : param
}
const result = test(true) // [true]
const result2 = test('hello') // ["hello"]
const result3 = test(['hello']) // ["hello"]
const result4 = test([true]) // [true]
顺便说一句,typescript 不能很好地处理变异值,它可能会导致错误