【发布时间】:2021-09-21 04:02:14
【问题描述】:
假设我有
declare function doSomething(...args: any[]): any
interface Example {
a: number
b: number
}
doSomething({a: 2, b: 1, c: 10} as Example)
这不会报告错误,因为该对象扩展了 Example 并且打字稿很高兴,所以我最终使用了一个丑陋的标识函数:
function cast<T>(arg: T) {
return arg
}
doSomething(cast<Example>({a: 2, b: 1, c: 10})) // yay, error
这让我很恼火,我需要实际调用 %^#% 无操作函数来进行正确的类型转换。我最终在每个需要它的文件中声明它,只是为了给 js 编译器更好的优化它的机会。
有什么不知道的ts魔法可以避免函数调用吗?
是的,我知道我可以做到:
const x: Example = {a: 2, b: 1, c: 10}
doSomething(x)
还有这个:
declare function doSomething(arg: Example): any
这真的不是重点。考虑以下 lambda:
const example = (i: number, j: number, k: number) => cast<Example>({a: 1, b: 2, c: 3})
正确设置类型而不导致我需要编写的标识函数
const example: (i: number, j: number, k: number) => Example = (i, j, k) => ({a: 1, b: 2, c: 3})
这不是很干燥
是的,我可以写
function example (i: number, j: number, k: number): Example {
return {a: 1, b: 2, c: 3}
}
再说一遍,不是重点
// 编辑
@thedude 刚刚在评论中用我不知道的 lambda 返回类型语法让我大吃一惊,还有一个我使用这种转换的例子
declare function doSomethingWithArray(arg: Example[]): void
doSomethingWithArray(cast<(Example | boolean)[]>([
{a: 1, b: 2},
false,
{a: 1, b: 2, c: 3}
]).filter(x => x) as Example[])
//编辑2
我似乎很难解释我想要什么,另一个例子:这个通用函数解决了过滤器示例问题
function filterFalse<T>(x: (T | false)[]) {
return x.filter(x => x) as Exclude<T, false>[]
}
doSomethingWithArray(filterFalse<Example>([
{a: 1, b: 2},
false,
{a: 1, b: 2, c: 3} // error
]))
但需要为这个特定任务定义一个专门的函数。我在问是否有一种通用的方法来强制对编译时文字进行严格的类型检查,而不会导致函数调用。这正是cast<T> 所做的,但在 js 输出中没有毫无意义的调用。
【问题讨论】:
-
你也可以写:
const example = (i: number, j: number, k: number): Example => ({a: 1, b: 2, c: 3}) -
最后一个sn-p有什么问题?为什么这不是重点?如果您编写的代码不使用
any,那么您应该很少需要像这样进行强制转换。 -
重点是我想要一个 lambda 声明而不是函数声明,这确实可以通过 @thedude 在上面的评论中所写的内容解决,请参阅编辑以获取另一个示例
-
@OtisVallone 在新的 sn-p 中,您仍然不需要
cast函数。filter函数可以作用于任何数组,因此您可以给它一个混合布尔值和Example对象的数组。 Typescript 已经推断出该数组的类型是(boolean | Example)[]。 -
@siride 过滤器推断文字对象(和布尔值)的联合数组,而不是(布尔值 | 示例)[]。除了一些我不知道的原因之外,即使这个
doSomethingWithArray([{a: 1, b: 2, c: 3}].filter(x => x))在c上也不会失败,而没有过滤器它会失败。
标签: typescript types type-assertion