TypeScript 中通用 ConsList 的类型错误
Type Error with Generic ConsList in TypeScript
我正在学习 TypeScript 的第 2 天,所以这可能是一个重复的问题(因为我可能不知道要搜索什么)。
我正在尝试做一些基本的 FP 练习来熟悉 TypeScript。这里我有一个带有构造函数的标准缺点列表类型:
type ConsList<T> =
null |
[T, ConsList<T>]
function cons<T>(head: T, tail: ConsList<T>): ConsList<T> {
return [head, tail];
}
function fromArray<T>(arr: Array<T>): ConsList<T> {
let xs: ConsList<T> = null;
for (let i = arr.length - 1; i >= 0; i--) {
xs = cons(arr[i], xs)
}
return xs;
}
还有一个文件夹:
function foldR<T, U>(
f: ((x: T, acc: U) => U),
acc: U,
xs: ConsList<T>): U {
if (xs === null) {
return acc;
}
else {
let [h, t] = xs
return f(h, foldR(f, acc, t));
}
}
当我尝试测试 rold 时,出现错误:
console.log(foldR((a, b) => cons(a, b), null, xs));
fold.ts 60 29 error 2322 Type 'ConsList<number>' is not assignable to type 'null'.
Type '[number, ConsList<number>]' is not assignable to type 'null'. ⮐ (typescript-tide)
非常感谢您指出我所缺少的内容!
我不确定我是否遵循了您的目标,但我看到了问题所在。
让我们从这个函数签名开始:
function foldR<T, U>(
f: ((x: T, acc: U) => U),
acc: U,
xs: ConsList<T>
): U
具体看U
。它是从参数 acc
中推断出来的,然后用在其他地方。
现在这里:
foldR((a, b) => cons(a, b), null, xs)
您通过 null
获得 acc
。所以 U
被推断为 null
.
现在打字稿试图强制执行该推理。这将我们带到:
f: ((x: T, acc: U) => U)
表示f
是returns U
的函数(推断为null
)。但是,您的函数 returns ConsList<T>
可能是 null
,也可能不是。函数类型不允许非空 return 值。这就是这个错误的意思:
Type 'ConsList<T>' is not assignable to type 'null'.
Type '[T, ConsList<T>]' is not assignable to type 'null'.(2322)
null
是预期的 return 类型,ConsList<T>
是不兼容的类型。
要解决此问题,您需要能够获取 foldR
来推断 U
的正确类型。你有几种方法可以做到这一点。
您可以将 null
值转换为正确的联合类型。
console.log(foldR(
(a, b) => cons(a, b),
null as ConsList<T>,
xs
));
或者您可以手动提供通用参数类型,因为您比推断的更了解:
console.log(foldR<T, ConsList<T>>(
(a, b) => cons(a, b),
null,
xs
));
I'd tried type annotation let empty: ConsList<number> = null;
which doesn't work, but let empty = null as ConsList<number>
works. What's the difference?
Typescript 在这里有点太聪明了。如果你这样做:
const ltr: 'a' | 'b' = 'a'
然后 typescript 知道 ltr
是 'a' | 'b'
,而且它应该缩小到 'a'
因为你分配给它一个常量值,它是该联合的成员.因此 Typescript 跟踪该细化并假设在该范围内 ltr
只能是 'a'
.
但是,当您这样做时:
const ltr = 'a' as 'a' | 'b'
然后 'a'
被转换为一些包含 'a'
的超类型。 as
加宽了类型。并且因为加宽发生在右侧,加宽的类型被分配给变量。
我正在学习 TypeScript 的第 2 天,所以这可能是一个重复的问题(因为我可能不知道要搜索什么)。
我正在尝试做一些基本的 FP 练习来熟悉 TypeScript。这里我有一个带有构造函数的标准缺点列表类型:
type ConsList<T> =
null |
[T, ConsList<T>]
function cons<T>(head: T, tail: ConsList<T>): ConsList<T> {
return [head, tail];
}
function fromArray<T>(arr: Array<T>): ConsList<T> {
let xs: ConsList<T> = null;
for (let i = arr.length - 1; i >= 0; i--) {
xs = cons(arr[i], xs)
}
return xs;
}
还有一个文件夹:
function foldR<T, U>(
f: ((x: T, acc: U) => U),
acc: U,
xs: ConsList<T>): U {
if (xs === null) {
return acc;
}
else {
let [h, t] = xs
return f(h, foldR(f, acc, t));
}
}
当我尝试测试 rold 时,出现错误:
console.log(foldR((a, b) => cons(a, b), null, xs));
fold.ts 60 29 error 2322 Type 'ConsList<number>' is not assignable to type 'null'.
Type '[number, ConsList<number>]' is not assignable to type 'null'. ⮐ (typescript-tide)
非常感谢您指出我所缺少的内容!
我不确定我是否遵循了您的目标,但我看到了问题所在。
让我们从这个函数签名开始:
function foldR<T, U>(
f: ((x: T, acc: U) => U),
acc: U,
xs: ConsList<T>
): U
具体看U
。它是从参数 acc
中推断出来的,然后用在其他地方。
现在这里:
foldR((a, b) => cons(a, b), null, xs)
您通过 null
获得 acc
。所以 U
被推断为 null
.
现在打字稿试图强制执行该推理。这将我们带到:
f: ((x: T, acc: U) => U)
表示f
是returns U
的函数(推断为null
)。但是,您的函数 returns ConsList<T>
可能是 null
,也可能不是。函数类型不允许非空 return 值。这就是这个错误的意思:
Type 'ConsList<T>' is not assignable to type 'null'.
Type '[T, ConsList<T>]' is not assignable to type 'null'.(2322)
null
是预期的 return 类型,ConsList<T>
是不兼容的类型。
要解决此问题,您需要能够获取 foldR
来推断 U
的正确类型。你有几种方法可以做到这一点。
您可以将 null
值转换为正确的联合类型。
console.log(foldR(
(a, b) => cons(a, b),
null as ConsList<T>,
xs
));
或者您可以手动提供通用参数类型,因为您比推断的更了解:
console.log(foldR<T, ConsList<T>>(
(a, b) => cons(a, b),
null,
xs
));
I'd tried type annotation
let empty: ConsList<number> = null;
which doesn't work, butlet empty = null as ConsList<number>
works. What's the difference?
Typescript 在这里有点太聪明了。如果你这样做:
const ltr: 'a' | 'b' = 'a'
然后 typescript 知道 ltr
是 'a' | 'b'
,而且它应该缩小到 'a'
因为你分配给它一个常量值,它是该联合的成员.因此 Typescript 跟踪该细化并假设在该范围内 ltr
只能是 'a'
.
但是,当您这样做时:
const ltr = 'a' as 'a' | 'b'
然后 'a'
被转换为一些包含 'a'
的超类型。 as
加宽了类型。并且因为加宽发生在右侧,加宽的类型被分配给变量。