- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我遇到了一个有趣的 TS 类型守卫的行为,想问问你是我必须接受它还是我做错了什么。我把最小的例子放在一起(嗯,接近最小)。
enum LegType {
LegA = 'LegA',
LegB = 'LegB',
}
interface LegA {
type: LegType.LegA
foo: string
}
interface LegB {
type: LegType.LegB
bar: string
}
type Leg = LegA | LegB
enum PlanType {
T = 'T',
C = 'C',
}
interface TPlan {
type: PlanType.T
legs: LegA[]
}
interface CPlan {
type: PlanType.C
legs: (LegA | LegB)[]
}
type Plan = TPlan | CPlan
const isLegA = (o: Leg): o is LegA => o.type === LegType.LegA
const getFoo = (plan: Plan): string | undefined => {
// const legs: Leg[] = plan.legs // With this line the code builds with no errors.
const legs = plan.legs // With this line the code contains error, the type of `legs` is resolved as: LegA[] | (LegA | LegB)[]
const someLegA = legs.find(isLegA)
return someLegA?.foo // Property 'foo' does not exist on type 'LegA | LegB'.
}
为什么需要添加 :Leg[]
?是否可以重写代码以便 TS 自己理解正确的类型是什么?
最佳答案
糟糕,我明白发生了什么,我认为这里唯一合理的答案是做你所做的:注释 legs
作为Leg[]
.
因此,library type signature对于 Array
的 find()
方法是 overloaded和接受 user-defined type guard 的重载回调并返回一个缩小的元素类型是 generic :
find<S extends T>(
predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any
): S | undefined;
find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;
当你不注释时 legs
, 它得到 union type Array<Leg> | Array<LegA>
.此类型被认为与 Array<Leg>
兼容但它不会自动处理它(这可能很好。Array<LegA>
不应该让你 push()
一个 LegB
到它上面,但 Array<Leg>
应该)。
这意味着 legs.find
的类型本身是签名不相同的函数的联合:
type LegsFind = {
<S extends LegA>(p: (this: void, v: LegA, i: number, o: LegA[]) => v is S, t?: any): S | undefined;
(p: (v: LegA, i: number, o: LegA[]) => unknown, t?: any): LegA | undefined;
} | {
<S extends Leg>(p: (this: void, v: Leg, i: number, o: Leg[]) => v is S, t?: any): S | undefined;
(p: (v: Leg, i: number, o: Leg[]) => unknown, t?: any): Leg | undefined;
};
在 TypeScript 3.3 之前,编译器会直接放弃并告诉您它不知道如何调用这样的函数联合。有人会告诉你改变Array<X> | Array<Y>
至 Array<X | Y>
如果您正在调用非变异方法,例如 find()
, 你会使用 Leg[]
继续前进。
引入 TypeScript 3.3 improved behavior for calling union types .在某些情况下,编译器可以采用函数联合并将其表示为采用 intersection 的单个函数。来自联盟每个成员的参数。您可以在相关的拉取请求中阅读更多相关信息,microsoft/TypeScript#29011 .
但是,there are cases when it can't do this :特别是如果联合的多个分支被重载或泛型函数。不幸的是 find()
,这就是你所处的情况。看起来编译器尝试想出一种方法来使它可调用,但它放弃了与用户定义类型保护缩小对应的通用签名并以“常规”结尾,可能是因为它们彼此兼容:
type LegsFind33 = (p: (v: LegA, i: number, o: Leg[]) => unknown, thisArg?: any) => Leg | undefined;
所以你调用成功了,没有发生收缩,你就遇到了问题。调用函数并集的问题没有完全解决;它的 GitHub 问题 microsoft/TypeScript#7294已关闭并标记为“重访”。
所以在重新审视之前,这里的建议仍然对待Array<X> | Array<Y>
喜欢Array<X | Y>
如果您正在调用非变异方法,例如 find()
... 使用 Leg[]
继续前进。
好的,希望对你有帮助;祝你好运!
关于typescript - TS 类型防护带复杂类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60441311/
如何将多个 TS 文件合并为一个具有正确时间戳的 TS 文件?我可以将文件合并为一个,而无需接触数据。这将生成一个可播放的文件,但时间戳不正确,因此不会显示时间线(例如在 VLC 中)。因此,我需要重
有一个视频,其实是一个HLS流(TS文件的序列) 我想取出一个 TS block 并用另一个替换它。 另一个 block 将使用相同的 FFMPEG 编码设置进行编码。 如果你想知道我为什么需要这个:
这段代码取自https://en.cppreference.com/w/cpp/utility/variant/visit using var_t = std::variant; template s
我刚刚开始使用 ts-node。这是一个非常方便的工具。运行时间看起来很清晰。但它不适用于 CLI 解决方案。我无法将参数传递到编译的脚本中。 ts-node --preserve-symlinks
如果您愿意花 2 美分来解决调用另一个文件中定义的函数的问题,我将不胜感激。我阅读了 Typescript 的文档,其中建议设置一个接口(interface)或一个模块,然后引用它,但我收到了与下面相
我在努力 tsc ts/game.ts --out test.js --module amd 在我在 webstorm 中的 typescript 项目上,但是控制台没有显示任何错误,也没有输出 t
我已经意识到有一段时间了,一些 typescript 文件有一个 .d.ts 而其他的只有一个 .ts 扩展名。 它们代表什么?有什么区别? 最佳答案 这些是 declaration files ,或
是否有一种简单的方法可以将std::variant中包含的数据移动到std::variant中? 我想可以通过一个额外的类模板来切换Ts...中的所有类型,但是我想知道是否存在一种更优雅的就地方法。
我是 Angular 的新手,正在查看文档,但我想我也应该在这里问我的问题。 我正在导出一个越来越大的类,因此我想将其分成两个文件,并将 d1、d2、d3 等存储在一个单独的文件中,然后将它们导入到
无法通过指定 ts.t 找到条目(ts 是时间戳类型) 挖oplog,想搞清楚一秒钟有多少操作。 无法通过指定时间戳字段找到条目,其他字段可以。$在蒙戈外壳中: > db.oplog.rs.findO
这是我的 Angular5 项目结构。 tsconfig.app.json 和package.json 都包含这个部分 "include": [ "/src/main.ts",
我在 Angular 10 中有一个项目,遇到了奇怪的 TS (TSLint) 错误。在我使用 $localize 的任何地方的 Visual Studio Code 中,我都收到错误消息 Canno
所以我创建了一个快速服务器,它获取一个 mp3 文件(现在存储在本地,但稍后将从 mongo db 中获取)并使用 ffmpeg 制作 .m3u8 和 .ts 文件。文件成功发送到客户端,在客户端播放
我有一个 MY_FILE.ts像这样的文件: const someFunction = (param: MY_NAMESPACE.PARAM) : boolean => { // DO SOMETHI
我过去常常在运行前编译用 TS 编写的 e2e Protractor 测试,但现在我想出了如何在运行时编译 ts 文件——ts-node 似乎是一个很好的工具。正如许多文章所说,我在 Protract
我不熟悉 mod-rewrite,我找不到任何类似的问题或解决方案。 非常感谢... 模板: {query1}_{query2}.ts ts.php?v={query1}&seg={query2} 例
我有 firestore.service.ts,在一种方法中,我在 firebase 中创建和更新了一个集合……离开该方法后,我更改了集合的“id”,但我需要这个“id”是没有丢失,因为我需要它到下一
DefinitelyTyped 有许多库的类型定义,但当 Javascript 实现与 Typescript 分离时,我常常找不到使用它们的好方法,比如当库通过 a 将自己分配给窗口的属性时 标记,
我正在寻找一种在我发布到 NPM 时忽略项目中所有 .ts 文件的好方法,我可以通过将以下内容添加到我的 .npmignore 文件中来做到这一点: *.ts 但是等等......实际上我想在我的项目
我的 Yarn 工作区结构如下: /project package.json /packages /app package.json webpack.confi
我是一名优秀的程序员,十分优秀!