function cast<R, T>(v: T): R {
return v as R;
~~~~~~
// Error
}
Run Code Online (Sandbox Code Playgroud)
所以我想做的是将类型v从 T 更改为 R。但是,我看到以下错误。
Conversion of type 'T' to type 'R' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
'T' is assignable to the constraint of type 'R', but 'R' could be instantiated with a different subtype of constraint '{}'.
Run Code Online (Sandbox Code Playgroud)
并且使用InstanceType<typeof R>也给了我一个错误。有人知道如何做到这一点吗?
jca*_*alz 13
TypeScript 的类型断言(采用 形式)expr as Type允许您告诉编译器表达式expr属于特定类型Type。编译器通常会很好地确定表达式应该是什么类型,但有时开发人员知道编译器不知道的东西,这就是您告诉编译器的方式。
请注意,这expr as Type 不会产生任何运行时效果。大多数情况下,TypeScript 中出现的类型仅描述运行时预期发生的情况;他们不会改变所发生的事情。静态类型系统本质上是从实际运行的 JavaScript 中删除的。
因此,expr as number是编译时类型断言,而不是运行时类型转换。例如,它不会执行类似的类型强制0+expr或类似的类型转换Number(expr)。
好的,类型断言让我们告诉编译器它应该将表达式视为什么类型。但编译器不会毫无怨言地自动接受所有此类断言。一般来说,如果它已经认为表达式可以分配给该类型,它将允许断言:
const foo = "foo" as string; // okay, widened from "foo" to string
Run Code Online (Sandbox Code Playgroud)
您可以将其视为“向上转型”,但可能更准确地描述为“扩大”。如果它认为表达式可能是该类型,它也将允许断言,因为断言的类型可以分配给它:
let bar = (Math.random() < 99 ? "bar" : 1) as string;
// okay, narrowed from string | number to string
Run Code Online (Sandbox Code Playgroud)
你可以将其视为“沮丧”,但可能更准确地描述为“缩小范围”。这些规则并不是全部,但总体思路是,如果断言扩大或缩小,编译器将允许断言。
编译器对它认为既不扩大也不缩小的断言犹豫不决。如果它认为您正在采用类型的表达式X并断言它的类型为Y,并且如果X两者都Y不能分配给另一个,则这些类型不会彼此“充分重叠”,并且您可能会错误地进行类型断言。T两个未指定的泛型类型参数和就是这种情况R。如果T extends R或R extends T为真,那就没问题,但就目前情况而言,它们可能是完全不相关的类型,因此断言被阻止:
function castBad<R, T>(v: T): R {
return v as R; // error!
// --> ~~~~~~
// Conversion of type 'T' to type 'R' may be a mistake because
// neither type sufficiently overlaps with the other.
// If this was intentional, convert the expression to 'unknown' first.
}
Run Code Online (Sandbox Code Playgroud)
错误消息向您提供成功所需的提示:对宽或窄的内容执行中间类型断言,以便编译器将每个步骤视为相关。所有类型都可以分配给unknowntype,因此您可以将其用作中间体:
function cast<R, T>(v: T): R {
return v as unknown as R; // okay
}
Run Code Online (Sandbox Code Playgroud)
随v as unknown你扩大T到unknown,然后随(v as unknown) as R你缩小unknown到R。您还可以使用以下任意一种:
v as never as R; // narrow to never, widen back to R
v as any as R; // narrow/widen to any, narrow/widen back to R
v as (T | R) as R; // widen to the union, narrow back to the other member
v as (T & R) as R; // narrow to the intersection, widen back to the other member
Run Code Online (Sandbox Code Playgroud)
所以,这应该可行。我担心像 这样的函数的用例cast(),因为它只是一个装扮成函数的类型断言,因此有同样的警告,即它并不是人们通常所说的“强制类型转换”:
const x = cast<number, string>("hello");
console.log(x.toFixed(1)); // okay at compile time, error at runtime. oops
Run Code Online (Sandbox Code Playgroud)
此外,如果您确实想要一个类型断言函数,那么T泛型参数不会做太多繁重的工作;它必须手动指定,但可以通过您传入的参数合理地推断出来。事实上,由于它仅用于参数的类型,您可以完全消除它:
function typeAssert<R>(v: any): R {
return v;
}
Run Code Online (Sandbox Code Playgroud)
然后当你使用它时,你只需要指定所需的返回类型:
const y = typeAssert<string>(Math.random() < 99 ? "okay" : 123); // string
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7544 次 |
| 最近记录: |