[英]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.由于编译器无法推断从函数参数解构的
from
、 to
和coords
变量的类型,因此它回退到推断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.考虑到在上面的代码中我完全拼错了
getBoundingClientRect
和to_rect.height
但编译器没有发现任何一个错误,因为to
和to_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
.您已经这样做了:
from
和to
属性应该是HTMLElement
, coords
属性应该是一个长度为 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
.错误准确地告诉您问题:
from
和to
属性很可能为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 会提前警告您类似的事情可能会在运行时发生,并让您有机会解决它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.