将类型不兼容的函数分配给 ref 属性
Assigning function with incompatible type to ref attribute
为什么下面的代码不会导致编译时错误?
import * as React from 'react';
export class Test extends React.Component {
private _onReferenceUpdated = (ref: HTMLCanvasElement) => {
ref.width = 4; // This could throw, when ref is null
};
render(): JSX.Element {
return (
<canvas ref={this._onReferenceUpdated} />
);
}
}
ref
属性被推断为
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string | ((instance: HTMLCanvasElement | null) => void) | React.RefObject<HTMLCanvasElement> | null | undefined
这似乎是正确的(string
有点奇怪,但我想这只是一般的属性)。 (ref: HTMLCanvasElement) => void
如何分配给 (instance: HTMLCanvasElement | null) => void
?
答案就在你的问题中。
如您所述,ref
的类型推断为:
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string | ((instance: HTMLCanvasElement | null) => void) | React.RefObject<HTMLCanvasElement> | null | undefined
这是一个“联合”类型,意味着任何由竖线 (|
) 分隔的类型在这里都是有效的。所以 ref
可以是以下任何一种:
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string
((instance: HTMLCanvasElement | null) => void)
React.RefObject<HTMLCanvasElement>
null
undefined
好吧,您已经定义了要传递给 ref
的 _onReferenceUpdated
属性,如下所示:
private _onReferenceUpdated = (ref: HTMLCanvasElement) => {
ref.width = 4; // This could throw, when ref is null
};
所以 _onReferenceUpdated
的类型是 (ref: HTMLCanvasElement) => void
,它很容易匹配我们上面的有效 ref
类型之一:((instance: HTMLCanvasElement | null) => void)
.
请注意,圆括号没有意义,它们只是为了提高可读性。另请注意,参数名称在一种类型中为“ref”而在另一种类型中为“instance”并不重要。重要的是函数参数的 order 和 type,以及 return 类型。
在 TypeScript 中,这样做是完全有效的:
let Foo = (a: string) => {}; // inferred type of Foo is "(a: string) => void"
Foo = (b: string) => {}; // no error; order and type of args and return type match
Foo = (c: number) => {}; // error! type of arguments don't match
免责声明:我只是进行了足够深入的研究,以大致了解问题所在。如果在其他问题中有合适的解释,或者有更好理解的人愿意给出,欢迎补充。
在 Typescript 2.6 中,添加了 strict function types 设置,现在可以逆变地检查函数参数。因此,
const f = (p: HTMLCanvasElement) => void p;
const g: (p: HTMLCanvasElement | null) => void = f;
启用该设置时出现错误。然而,可悲的是,由于似乎是 design limitation,例如TSX 中的 ref
道具:
there is no way to tell TypeScript that the "ref" prop actually is contravariant
接下来是 ,或者换句话说,ref
的行为就像 strictFunctionChecks
被禁用一样。然后,HTMLCanvasElement
是 HTMLCanvasElement | null
的子类型,并被接受。
当遵循类型定义时,这也是可见的,这导致:
type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
我觉得这很可悲(特别是,这个 hack 在类型注释中不可见,至少在 vscode 中不可见),欢迎任何适当的解决方案或关于该主题的更新。至少,我正在考虑一个 ESLint 打字稿规则,它以硬编码的方式强制传递给 ref
的任何函数的参数可以为空。
为什么下面的代码不会导致编译时错误?
import * as React from 'react';
export class Test extends React.Component {
private _onReferenceUpdated = (ref: HTMLCanvasElement) => {
ref.width = 4; // This could throw, when ref is null
};
render(): JSX.Element {
return (
<canvas ref={this._onReferenceUpdated} />
);
}
}
ref
属性被推断为
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string | ((instance: HTMLCanvasElement | null) => void) | React.RefObject<HTMLCanvasElement> | null | undefined
这似乎是正确的(string
有点奇怪,但我想这只是一般的属性)。 (ref: HTMLCanvasElement) => void
如何分配给 (instance: HTMLCanvasElement | null) => void
?
答案就在你的问题中。
如您所述,ref
的类型推断为:
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string | ((instance: HTMLCanvasElement | null) => void) | React.RefObject<HTMLCanvasElement> | null | undefined
这是一个“联合”类型,意味着任何由竖线 (|
) 分隔的类型在这里都是有效的。所以 ref
可以是以下任何一种:
(JSX attribute) React.ClassAttributes<HTMLCanvasElement>.ref?: string
((instance: HTMLCanvasElement | null) => void)
React.RefObject<HTMLCanvasElement>
null
undefined
好吧,您已经定义了要传递给 ref
的 _onReferenceUpdated
属性,如下所示:
private _onReferenceUpdated = (ref: HTMLCanvasElement) => {
ref.width = 4; // This could throw, when ref is null
};
所以 _onReferenceUpdated
的类型是 (ref: HTMLCanvasElement) => void
,它很容易匹配我们上面的有效 ref
类型之一:((instance: HTMLCanvasElement | null) => void)
.
请注意,圆括号没有意义,它们只是为了提高可读性。另请注意,参数名称在一种类型中为“ref”而在另一种类型中为“instance”并不重要。重要的是函数参数的 order 和 type,以及 return 类型。
在 TypeScript 中,这样做是完全有效的:
let Foo = (a: string) => {}; // inferred type of Foo is "(a: string) => void"
Foo = (b: string) => {}; // no error; order and type of args and return type match
Foo = (c: number) => {}; // error! type of arguments don't match
免责声明:我只是进行了足够深入的研究,以大致了解问题所在。如果在其他问题中有合适的解释,或者有更好理解的人愿意给出,欢迎补充。
在 Typescript 2.6 中,添加了 strict function types 设置,现在可以逆变地检查函数参数。因此,
const f = (p: HTMLCanvasElement) => void p;
const g: (p: HTMLCanvasElement | null) => void = f;
启用该设置时出现错误。然而,可悲的是,由于似乎是 design limitation,例如TSX 中的 ref
道具:
there is no way to tell TypeScript that the "ref" prop actually is contravariant
接下来是 ref
的行为就像 strictFunctionChecks
被禁用一样。然后,HTMLCanvasElement
是 HTMLCanvasElement | null
的子类型,并被接受。
当遵循类型定义时,这也是可见的,这导致:
type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
我觉得这很可悲(特别是,这个 hack 在类型注释中不可见,至少在 vscode 中不可见),欢迎任何适当的解决方案或关于该主题的更新。至少,我正在考虑一个 ESLint 打字稿规则,它以硬编码的方式强制传递给 ref
的任何函数的参数可以为空。