简体   繁体   English

TypeScript:没有接口的函数

[英]TypeScript: functions without interface

Is it allowed to use function props without any interface?是否允许使用没有任何接口的功能道具?

I have a function with properties:我有一个具有属性的函数:

from - HTML Element from - HTML 元素

to - HTML Element to - HTML 元素

coords - Array [2, 2] coords - 数组 [2, 2]

export const adjustElements = ({ from, to, coords }) => {
    let to_rect = to.getBoundingClientRect(),
        width = to_rect.width * ((coords[0] - 1) * 0.5),
        height = to_rect.height * ((coords[1] - 1) * 0.5);

    from.style.top = (to_rect.top + height) + "px";
    from.style.left = (to_rect.left + width) + "px";
}

But when I run the code I get following errors:但是当我运行代码时,我收到以下错误:

Binding element 'from' implicitly has an 'any' type.

Binding element 'to' implicitly has an 'any' type.

Binding element 'coords' implicitly has an 'any' type.

It happens because that I didn't add any interface to the function, but the problem is that I have a lot of functions like this, but with different parameters, so writing to everyone a new interface would be crazy... Is there a way where typescript could just stop requiring an interface for every function?之所以出现是因为我没有给函数添加任何接口,但问题是我有很多这样的函数,但是参数不同,所以写给大家一个新的接口会很疯狂......有没有打字稿可以停止为每个功能需要一个接口的方式?

EDIT: As jcalz pointed out in a comment, the answer I've given isn't valid TypeScript.编辑:正如 jcalz 在评论中指出的那样,我给出的答案不是有效的 TypeScript。 I had missed that you were passing a single argument wrapped in {} rather than passing in three separate arguments.我错过了您传递包裹在{}的单个参数而不是传递三个单独参数的情况。


You need to tell TypeScript what the types of your function's arguments are meant to be.你需要告诉 TypeScript 你的函数参数的类型是什么。 If you don't, and TypeScript can't tell somehow (eg if they had a default value), then it will infer their type as any .如果不这样做,并且 TypeScript 无法以某种方式告诉(例如,它们是否具有默认值),那么它将推断它们的类型为any But the default compiler settings prevent implicit any types.但是默认的编译器设置会阻止隐式任何类型。

You don't need to use an interface, you can do this:你不需要使用接口,你可以这样做:

export const adjustElements = ({ from: HTMLElement, to: HTMLElement, coords: [number, number] }) => {

Since the compiler is unable to infer the types of the from , to , and coords variables destructured from the function parameter, it falls back to inferring the any type which is intentionally unsafe and allows you to do almost anything with no further error.由于编译器无法推断从函数参数解构的fromtocoords变量的类型,因此它回退到推断any故意不安全的类型,并允许您执行几乎任何操作而不会出现进一步错误。 Assuming you've got the --strict suite of compiler features enabled (and you probably should) or even just the --noImplicitAny compiler option enabled, this automatic fallback to any will generate a warning, so that you are completely aware that the loss of type safety is happening.假设您已经启用--strict编译器功能套件(您可能应该)或者甚至只是启用--noImplicitAny编译器选项,这种自动回--noImplicitAny any将生成警告,以便您完全意识到损失类型安全正在发生。


The right thing to do is to annotate the function parameter to tell the compiler what type it will be.正确的做法是注释函数参数以告诉编译器它将是什么类型。 If you want to use any and just silence the warning, you can do so explicitly:如果你使用any并且只是让警告静音,你可以明确地这样做:

export const adjustElements = ({ from, to, coords }: any) => {
  let to_rect = to.getBoundingCleintRect(),
    width = to_rect.width * ((coords[0] - 1) * 0.5),
    height = to_rect.heigth * ((coords[1] - 1) * 0.5);

  from.style.top = (to_rect.top + height) + "px";
  from.style.left = (to_rect.left + width) + "px";
} // no error

but this allows all kinds of crazy calls to adjustElements where you'd probably want to see a compiler error:但这允许对adjustElements进行各种疯狂调用,您可能希望在其中看到编译器错误:

adjustElements("oopsie"); // no error

as well as allowing crazy implementations ;以及允许疯狂的实现 consider that in the above code I completely misspelled getBoundingClientRect and to_rect.height but the compiler failed to catch either mistake, because both to and to_rect are of type any and the compiler gives up on worrying what you're doing with those.考虑到在上面的代码中我完全拼错了getBoundingClientRectto_rect.height但编译器没有发现任何一个错误,因为toto_rect都是any类型,编译器放弃了担心你在做什么。

So you don't want to do that.所以你不想这样做。


Instead, you should think about what type the function parameter must be.相反,您应该考虑函数参数必须是什么类型。 You've already done this: the from and to properties should be HTMLElement , and the coords property should be a tuple of length two where each element is a number .您已经这样做了: fromto属性应该是HTMLElementcoords属性应该是一个长度为 2 的元组,其中每个元素都是一个number

You could make a named interface for this object type, but if you're only ever going to use it once, you might not want to bother giving it an explicit name.您可以为这个对象类型创建一个命名interface ,但如果您只打算使用它一次,您可能不想费心给它一个明确的名称。 In that case you can just use an anonymous object type :在这种情况下,您可以只使用匿名对象类型

export const adjustElements = ({ from, to, coords }:
  { from: HTMLElement, to: HTMLElement, coords: [number, number] }
) => {
  let to_rect = to.getBoundingClientRect(),
    width = to_rect.width * ((coords[0] - 1) * 0.5),
    height = to_rect.height * ((coords[1] - 1) * 0.5);

  from.style.top = (to_rect.top + height) + "px";
  from.style.left = (to_rect.left + width) + "px";
}

Now this works and the compiler will catch misspellings, and it will also catch bogus calls to adjustElements() :现在这adjustElements() ,编译器将捕获拼写错误,并且还将捕获对adjustElements()虚假调用:

adjustElements("oopsie"); // error
// Argument of type 'string' is not assignable to parameter of 
// type '{ from: HTMLElement; to: HTMLElement; coords: [number, number]; }

That's an error because you gave it a string where it expected your anonymous object type, and a string is not appropriate.这是一个错误,因为您在它期望您的匿名对象类型的地方给了它一个string ,而一个string是不合适的。


Note that the compiler considers the following a bogus call also:请注意,编译器还将以下内容视为虚假调用:

adjustElements({
  from: document.querySelector(".wheel-pointer"),
//~~~~ <-- Type 'HTMLElement | null' is not assignable to type 'HTMLElement'
  to: document.querySelector(".wheel"),
//~~ <-- Type 'HTMLElement | null' is not assignable to type 'HTMLElement'
  coords: [2, 1]
}) // error!

The errors tell you exactly the problem: the from and to properties may well be null , because document.querySelector() sometimes returns null .错误准确地告诉您问题: fromto属性很可能为null ,因为document.querySelector()有时返回null The compiler does not know that anything of class "wheel-pointer" or "wheel" exists in the document, so it's an error.编译器不知道文档中存在"wheel-pointer""wheel"类的任何内容,因此这是一个错误。 If you want to make a call like this you will need to either check that those aren't null , or assert that they aren't.如果您想进行这样的调用,您将需要检查它们是否不是null ,或者断言它们不是。 A check could look like this (using truthiness narrowing ):检查可能如下所示(使用真实性缩小):

const wheelPointerElement = document.querySelector(".wheel-pointer");
if (!wheelPointerElement) throw new Error("OH NO");
const wheelElement = document.querySelector(".wheel");
if (!wheelElement) throw new Error("WHY ME");

adjustElements({
  from: wheelPointerElement,
  to: wheelElement,
  coords: [2, 1]
}) // okay

While an assertion could look like this: (using the non-null assertion operator ! ):虽然断言可能如下所示:(使用非空断言运算符! ):

adjustElements({
  from: document.querySelector(".wheel-pointer")!,
  to: document.querySelector(".wheel")!,
  coords: [2, 1]
}) // okay

It's too far afield from the original question to explain the differences between checking and asserting, pros and cons of each, and the different ways to do them.与原始问题相距甚远,无法解释检查和断言之间的差异,每种方法的优缺点以及执行它们的不同方法。 Just know that these error situations are part of the point of TypeScript in the first place.只要知道这些错误情况首先是 TypeScript 重点的一部分。 In your original JavaScript code, you'd have to wait until runtime to see errors on adjustElements(null, null, [2, 1]) .在您的原始 JavaScript 代码中,您必须等到运行时才能看到adjustElements(null, null, [2, 1]) TypeScript warns you ahead of time that something like that might happen at runtime and gives you a chance to address it. TypeScript 会提前警告您类似的事情可能会在运行时发生,并让您有机会解决它。

Playground link to code Playground 链接到代码

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

相关问题 如何在typescript中实现一个具有多个匿名函数的接口 - How to implement an interface with multiple anonymous functions in typescript 打字稿-在不实现接口父级的情况下实现接口 - Typescript - implementing an interface without implementing the interfaces parents 在 Typescript 中创建接口而不指定属性名称 - Create Interface in Typescript without specifying property name 编译打字稿而不转换异步函数 - Compile typescript without transpiling async functions JavaScript / TypeScript Array interface [],按类型分组以发送多种功能中的一种 - JavaScript/TypeScript Array interface[] , group by type to send 1 of many functions 打字稿:定义没有特定键和链对象的接口 - Typescript: define interface without specific keys & chain objects 在Angular 5 / TypeScript中获取类(接口)属性,而不分配默认值 - Get class (interface) properties in Angular 5 / TypeScript without assigning a default value TypeScript:像数组一样初始化接口(不指定成员名) - TypeScript: Initialize interface like array (without specifying member name) 如何使用没有 inheritance 的其他两个接口在 Typescript 中创建接口? - How to create an interface in Typescript using two other interfaces without inheritance? typescript 中的功能 - Functions in typescript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM