简体   繁体   English

Typescript 类型不匹配没有编译时错误

[英]No compile time error for Typescript type mismatch

I have a function defined like this:我有一个 function 定义如下:

export async function removeUser(deleteUserId: Types.ObjectId)

When I mistakenly called this function and pass a Mongoose object's id parameter, which is a string, it triggered a runtime exception further in the code when I tried to use the .equals() method which exists on an ObjectId but not on a string:当我错误地调用这个 function 并传递一个 Mongoose 对象的id参数时,它是一个字符串,当我尝试使用.equals()方法时,它在代码中进一步触发了运行时异常,该方法存在于 ObjectId 而不是字符串上:

await removeUser(deleteUser.id);

When I corrected this by passing the ObjectId, everything worked fine:当我通过传递 ObjectId 更正此问题时,一切正常:

await removeUser(deleteUser._id);

My question is, why didn't I get a compile time error from Typescript if the argument is specified as an ObjectId, but a string is being passed?我的问题是,如果参数指定为 ObjectId,但传递的是字符串,为什么我没有从 Typescript 收到编译时错误?

Edit: I see that the .id is defined as any , not as a string .编辑:我看到.id被定义为any ,而不是string I suspect that will factor into the answer?我怀疑这会影响答案?

Yep, if we can somehow check for any , then we can make sure that values of type any cannot be passed:是的,如果我们能以某种方式检查 any ,那么我们就可以确保不能传递any类型的值:

type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N;

export async function removeUser<Id extends Types.ObjectId>(deleteUserId: IfAny<Id, never, Id>) {

So if we pass in any , the type of deleteUserId will turn into never :所以如果我们传入anydeleteUserId的类型就会变成never

await removeUser(deleteUser.id);  // error, type 'any' is not assignable to type 'never'
await removeUser(deleteUser._id); // ok

Playground操场

I see that the.id is defined as any, not as a string.我看到 the.id 被定义为任何,而不是字符串。

Values of type any allow assignment to any type. any类型的值允许分配给任何类型。

const n: number =  'string' as any // fine

It's an escape hatch from the type system.这是类型系统的逃生舱口。 So any is not typesafe and should be avoided at all costs.所以any不是类型安全的,应该不惜一切代价避免使用。

See Documentation: 请参阅文档:

The compiler effectively treats any as “please turn off type checking for this thing”.编译器有效地将 any 视为“请关闭对此事物的类型检查”。 It is similar to putting an @ts-ignore comment around every usage of the variable.它类似于在变量的每个用法周围放置一个@ts-ignore 注释。

Typescript types exist only in compile time, not in runtime. Typescript 类型只存在于编译时,不存在于运行时。 Therefore, Typescript type system is not sound -- it cannot guarantee you that if your program compiles, it will not throw any error in runtime.因此,Typescript 类型系统并不健全——它不能保证如果您的程序编译通过,它不会在运行时抛出任何错误。

Back to your question, if a variable type is any , you can do anything with it, and Typescript will not even blink.回到你的问题,如果一个变量类型是any ,你可以用它做任何事情,而 Typescript 甚至不会眨眼。 You should use any type with an extreme caution.您应该极其谨慎地使用any类型。

For example, if you have a variable obj of type any :例如,如果您有一个类型为any的变量obj

  • You could assign obj to any other variable (except of type never )您可以将obj分配给任何其他变量(类型never除外)
  • You could access any fields on obj eg obj.abc.d您可以访问obj上的任何字段,例如obj.abc.d
  • You could pass it to any function, in particular that expecting string您可以将它传递给任何 function,特别是那个期待的string

Code example : 代码示例

function onlyAcceptingNumber(a: number) {}

export async function doSomething(obj: any){
  // I can do this:
  const a = obj.a * obj.b;
  // I can also do this:
  console.log(obj.a.b.c.d);
  // and I can call onlyAcceptingNumber with obj
  onlyAcceptingNumber(obj);
}

// but of course this could fail in runtime:
doSomething("123");
doSomething({ name: "John" });

In the example above, the doSomething function would compile, and both calls to it would compile, but of course if we run everything, it would fail in runtime.在上面的示例中, doSomething function 会编译,并且对它的两次调用都会编译,但当然如果我们运行所有内容,它会在运行时失败。

To battle this, you can use eg ESLint's no-explicit-any rule, and in general only use any as a last resort为了解决这个问题,您可以使用例如ESLint 的 no-explicit-any规则,并且通常只使用any作为最后的手段

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM